[Win32SS|UxTheme]
authorJames Tabor <james.tabor@reactos.org>
Tue, 1 Sep 2015 22:10:13 +0000 (22:10 +0000)
committerJames Tabor <james.tabor@reactos.org>
Tue, 1 Sep 2015 22:10:13 +0000 (22:10 +0000)
- Move Menu to server side. See CORE-7797 and CORE-8299.
- This was for speed while moving windows about the desktop and fixed test results too.

svn path=/trunk/; revision=68904

41 files changed:
reactos/dll/win32/uxtheme/nonclient.c
reactos/dll/win32/uxtheme/themehooks.c
reactos/include/reactos/undocuser.h
reactos/win32ss/CMakeLists.txt
reactos/win32ss/include/ntuser.h
reactos/win32ss/user/ntuser/callback.c
reactos/win32ss/user/ntuser/class.c
reactos/win32ss/user/ntuser/defwnd.c
reactos/win32ss/user/ntuser/desktop.c
reactos/win32ss/user/ntuser/draw.c
reactos/win32ss/user/ntuser/focus.c
reactos/win32ss/user/ntuser/keyboard.c
reactos/win32ss/user/ntuser/menu.c
reactos/win32ss/user/ntuser/menu.h
reactos/win32ss/user/ntuser/message.c
reactos/win32ss/user/ntuser/misc.c
reactos/win32ss/user/ntuser/msgqueue.c
reactos/win32ss/user/ntuser/msgqueue.h
reactos/win32ss/user/ntuser/nonclient.c
reactos/win32ss/user/ntuser/ntstubs.c
reactos/win32ss/user/ntuser/painting.c
reactos/win32ss/user/ntuser/painting.h
reactos/win32ss/user/ntuser/scroll.h
reactos/win32ss/user/ntuser/scrollbar.c
reactos/win32ss/user/ntuser/scrollex.c
reactos/win32ss/user/ntuser/userfuncs.h
reactos/win32ss/user/ntuser/win32.h
reactos/win32ss/user/ntuser/window.c
reactos/win32ss/user/ntuser/window.h
reactos/win32ss/user/ntuser/winpos.c
reactos/win32ss/user/ntuser/winpos.h
reactos/win32ss/user/ntuser/winsta.c
reactos/win32ss/user/rtl/text.c [new file with mode: 0644]
reactos/win32ss/user/user32/CMakeLists.txt
reactos/win32ss/user/user32/misc/usrapihk.c
reactos/win32ss/user/user32/user32.spec
reactos/win32ss/user/user32/windows/defwnd.c
reactos/win32ss/user/user32/windows/draw.c
reactos/win32ss/user/user32/windows/font.c
reactos/win32ss/user/user32/windows/menu.c
reactos/win32ss/user/user32/windows/nonclient.c

index 4cb7079..f64717f 100644 (file)
@@ -1070,7 +1070,13 @@ ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndPr
     {
     case WM_NCPAINT:
         return ThemeHandleNCPaint(hWnd, (HRGN)wParam);
+    //
+    // WM_NCUAHDRAWCAPTION : wParam are DC_* flags.
+    //
     case WM_NCUAHDRAWCAPTION:
+    //
+    // WM_NCUAHDRAWFRAME : wParam is HDC, lParam are DC_ACTIVE and or DC_REDRAWHUNGWND.
+    //
     case WM_NCUAHDRAWFRAME:
     case WM_NCACTIVATE:
         ThemeHandleNCPaint(hWnd, (HRGN)1);
index f5101e0..20b541d 100644 (file)
@@ -186,12 +186,6 @@ ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {      
     if(!IsAppThemed())
     {
-        if (Msg == WM_NCUAHDRAWCAPTION)
-        {
-            user32ApiHook.DrawCaption(hWnd, NULL, NULL, 0);
-            return 0;
-        }
-
         return user32ApiHook.DefWindowProcW(hWnd, 
                                             Msg, 
                                             wParam, 
@@ -210,12 +204,6 @@ ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {
     if(!IsAppThemed())
     {
-        if (Msg == WM_NCUAHDRAWCAPTION)
-        {
-            user32ApiHook.DrawCaption(hWnd, NULL, NULL, 0);
-            return 0;
-        }
-
         return user32ApiHook.DefWindowProcA(hWnd, 
                                             Msg, 
                                             wParam, 
index 50f1465..76bc938 100644 (file)
@@ -43,6 +43,7 @@ extern "C" {
 #define WM_LBTRACKPOINT     0x00000131
 #define LB_CARETON          0x000001a3
 #define LB_CARETOFF         0x000001a4
+#define MN_SETHMENU         0x000001e0
 #define WM_DROPOBJECT       0x0000022A
 #define WM_QUERYDROPOBJECT  0x0000022B
 #define WM_BEGINDRAG        0x0000022C
@@ -60,6 +61,9 @@ extern "C" {
 #define DCX_KEEPLAYOUT   0x40000000
 #define DCX_PROCESSOWNED 0x80000000
 
+/* Non SDK TPM types.*/
+#define TPM_SYSTEM_MENU  0x00000200
+
 /* NtUserCreateWindowEx dwFlags bits. */
 #define NUCWE_ANSI       0x00000001
 #define NUCWE_SIDEBYSIDE 0x40000000
@@ -132,7 +136,20 @@ extern "C" {
 //
 // Undocumented flags for DrawCaptionTemp
 //
+#define DC_NOVISIBLE 0x0800
 #define DC_NOSENDMSG 0x2000
+#define DC_FRAME     0x8000  // Missing from WinUser.H!
+
+#define DC_DRAWCAPTIONMD  0x10000000
+#define DC_REDRAWHUNGWND  0x20000000
+#define DC_DRAWFRAMEMD    0x80000000
+
+//
+// Undocumented states for DrawFrameControl
+//
+#define DFCS_MENUARROWUP   0x0008
+#define DFCS_MENUARROWDOWN 0x0010
+
 
 #define STARTF_SCRNSAVER 0x80000000
 
index 24477f2..ca75c75 100644 (file)
@@ -149,6 +149,7 @@ list(APPEND SOURCE
     user/ntuser/winpos.c
     user/ntuser/winsta.c
     user/ntuser/object.c
+    user/rtl/text.c
     gdi/ntgdi/arc.c
     gdi/ntgdi/bezier.c
     gdi/ntgdi/bitblt.c
index 47e16ef..7be8260 100644 (file)
@@ -375,6 +375,9 @@ typedef struct tagMENULIST
 /* Hack */
 #define MNF_SYSMENU    0x0200
 
+/* (other FocusedItem values give the position of the focused item) */
+#define NO_SELECTED_ITEM 0xffff
+
 typedef struct tagMENU
 {
     PROCDESKHEAD head;
@@ -3515,58 +3518,6 @@ NtUserGetMonitorInfo(
 
 /* Should be done in usermode */
 
-/* (other FocusedItem values give the position of the focused item) */
-#define NO_SELECTED_ITEM 0xffff
-
-typedef struct tagROSMENUINFO
-{
-    /* ----------- MENUINFO ----------- */
-    DWORD cbSize;
-    DWORD fMask;
-    DWORD dwStyle;
-    UINT cyMax;
-    HBRUSH  hbrBack;
-    DWORD dwContextHelpID;
-    ULONG_PTR dwMenuData;
-    /* ----------- Extra ----------- */
-    ULONG fFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
-    UINT iItem; /* Currently focused item */
-    UINT cItems; /* Number of items in the menu */
-    WORD cxMenu; /* Width of the whole menu */
-    WORD cyMenu; /* Height of the whole menu */
-    ULONG cxTextAlign;
-    PWND spwndNotify; /* window receiving the messages for ownerdraw */
-    INT iTop;
-    INT iMaxTop;
-    DWORD dwArrowsOn:2;
-
-    HMENU Self; /* Handle of this menu */
-    HWND Wnd; /* Window containing the menu */
-    BOOL TimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
-} ROSMENUINFO, *PROSMENUINFO;
-
-typedef struct tagROSMENUITEMINFO
-{
-    /* ----------- MENUITEMINFOW ----------- */
-    UINT cbSize;
-    UINT fMask;
-    UINT fType;
-    UINT fState;
-    UINT wID;
-    HMENU hSubMenu;
-    HBITMAP hbmpChecked;
-    HBITMAP hbmpUnchecked;
-    DWORD dwItemData;
-    LPWSTR dwTypeData;
-    UINT cch;
-    HBITMAP hbmpItem;
-    /* ----------- Extra ----------- */
-    RECT Rect; /* Item area (relative to menu window) */
-    UINT dxTab; /* X position of text after Tab */
-    LPWSTR lpstr; /* Copy of the text pointer in MenuItem->Text */
-    SIZE maxBmpSize; /* Maximum size of the bitmap items in MIIM_BITMAP state */
-} ROSMENUITEMINFO, *PROSMENUITEMINFO;
-
 HMONITOR
 NTAPI
 NtUserMonitorFromPoint(
index 7ba7209..fbad4a2 100644 (file)
@@ -393,6 +393,8 @@ co_IntCallWindowProc(WNDPROC Proc,
           case WM_WINDOWPOSCHANGING:
           case WM_SIZING:
           case WM_MOVING:
+          case WM_MEASUREITEM:
+          case WM_NEXTMENU:
             TRACE("Copy lParam, Message %u Size %d lParam %d!\n", Message, lParamBufferSize, lParam);
             if (InSendMessage)
                // Copy into kernel space.
index b39b7cf..29db65c 100644 (file)
@@ -2556,6 +2556,15 @@ InvalidParameter:
                                       Offset,
                                       dwNewLong,
                                       Ansi);
+            switch(Offset)
+            {
+               case GCLP_HICONSM:
+               case GCLP_HICON:
+               {
+                  if (Ret && Ret != dwNewLong)
+                     UserPaintCaption(Window, DC_ICON);
+               }
+            }
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
index 410019a..0fccbbc 100644 (file)
 
 DBG_DEFAULT_CHANNEL(UserDefwnd);
 
+INT WINAPI DrawTextExWorker( HDC hdc, LPWSTR str, INT i_count,
+                        LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp );
+
+INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags )
+{
+    DRAWTEXTPARAMS dtp;
+
+    memset (&dtp, 0, sizeof(dtp));
+    dtp.cbSize = sizeof(dtp);
+    if (flags & DT_TABSTOP)
+    {
+        dtp.iTabLength = (flags >> 8) & 0xff;
+        flags &= 0xffff00ff;
+    }
+    return DrawTextExWorker(hdc, (LPWSTR)str, count, rect, flags, &dtp);
+}
+
 
 HBRUSH FASTCALL
 DefWndControlColor(HDC hDC, UINT ctlType)
@@ -171,6 +188,19 @@ DefWndHandleSysCommand(PWND pWnd, WPARAM wParam, LPARAM lParam)
            }
         }
         break;
+//      case SC_DEFAULT:
+      case SC_MOUSEMENU:
+        {
+          POINT Pt;
+          Pt.x = (short)LOWORD(lParam);
+          Pt.y = (short)HIWORD(lParam);
+          MENU_TrackMouseMenuBar(pWnd, wParam & 0x000f, Pt);
+        }
+       break;
+
+      case SC_KEYMENU:
+        MENU_TrackKbdMenuBar(pWnd, wParam, (WCHAR)lParam);
+       break;
 
 
       default:
@@ -362,6 +392,138 @@ VOID FASTCALL DefWndPrint( PWND pwnd, HDC hdc, ULONG uFlags)
     co_IntSendMessage(UserHMGetHandle(pwnd), WM_PRINTCLIENT, (WPARAM)hdc, uFlags);
 }
 
+BOOL
+UserPaintCaption(PWND pWnd, INT Flags)
+{
+  BOOL Ret = FALSE;
+
+  if ( pWnd->style & WS_VISIBLE && (pWnd->style & WS_CAPTION) == WS_CAPTION )
+  {
+  
+      if (pWnd->state & WNDS_HASCAPTION && pWnd->head.pti->MessageQueue == gpqForeground)
+         Flags |= DC_ACTIVE;
+    /* 
+     * When themes are not enabled we can go on and paint the non client area.
+     * However if we do that with themes enabled we will draw a classic frame.
+     * This is sovled by sending a themes specific message to notify the themes
+     * engine that the caption needs to be redrawn 
+     */
+      if (gpsi->dwSRVIFlags & SRVINFO_APIHOOK)
+      {
+        /* 
+         * This will cause uxtheme to either paint the themed caption or call
+         * RealUserDrawCaption in order to draw the classic caption when themes
+         * are disabled but the themes service is enabled
+         */
+         co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCUAHDRAWCAPTION, Flags, 0);
+      }
+      else
+      {
+         HDC hDC = UserGetDCEx(pWnd, NULL, DCX_WINDOW|DCX_USESTYLE);
+         UserDrawCaptionBar(pWnd, hDC, Flags);
+         UserReleaseDC(pWnd, hDC, FALSE);
+      }
+      Ret = TRUE;
+   }
+   // Support window tray
+   return Ret;
+}
+
+// WM_SETICON
+LRESULT FASTCALL
+DefWndSetIcon(PWND pWnd, WPARAM wParam, LPARAM lParam)
+{
+    HICON hIcon, hIconSmall, hIconOld;
+
+    if ( wParam > ICON_SMALL2 )
+    {  
+        EngSetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    hIconSmall = UserGetProp(pWnd, gpsi->atomIconSmProp);
+    hIcon      = UserGetProp(pWnd, gpsi->atomIconProp);
+
+    hIconOld = wParam == ICON_BIG ? hIcon : hIconSmall;
+
+    switch(wParam)
+    {
+        case ICON_BIG:
+            hIcon = (HICON)lParam;
+            break;
+        case ICON_SMALL:
+            hIconSmall = (HICON)lParam;
+            break;
+        case ICON_SMALL2:
+            ERR("FIXME: Set ICON_SMALL2 support!\n");
+        default:
+            break;
+    }
+
+    IntSetProp(pWnd, gpsi->atomIconProp, hIcon);
+    IntSetProp(pWnd, gpsi->atomIconSmProp, hIconSmall);
+
+    if ((pWnd->style & WS_CAPTION ) == WS_CAPTION)
+       UserPaintCaption(pWnd, DC_ICON);
+
+    return (LRESULT)hIconOld;
+}
+
+LRESULT FASTCALL
+DefWndGetIcon(PWND pWnd, WPARAM wParam, LPARAM lParam)
+{
+    HICON hIconRet;
+    if ( wParam > ICON_SMALL2 )
+    {
+        EngSetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    switch(wParam)
+    {
+        case ICON_BIG:
+            hIconRet = UserGetProp(pWnd, gpsi->atomIconProp);
+            break;
+        case ICON_SMALL:
+        case ICON_SMALL2:
+            hIconRet = UserGetProp(pWnd, gpsi->atomIconSmProp);
+            break;
+        default:
+            break;
+    }
+    return (LRESULT)hIconRet;
+}
+
+VOID FASTCALL
+DefWndScreenshot(PWND pWnd)
+{
+    RECT rect;
+    HDC hdc;
+    INT w;
+    INT h;
+    HBITMAP hbitmap;
+    HDC hdc2;
+    SETCLIPBDATA scd = {FALSE, FALSE};
+
+    UserOpenClipboard(UserHMGetHandle(pWnd));
+    UserEmptyClipboard();
+
+    hdc = UserGetWindowDC(pWnd);
+    IntGetWindowRect(pWnd, &rect);
+    w = rect.right - rect.left;
+    h = rect.bottom - rect.top;
+
+    hbitmap = NtGdiCreateCompatibleBitmap(hdc, w, h);
+    hdc2 = NtGdiCreateCompatibleDC(hdc);
+    NtGdiSelectBitmap(hdc2, hbitmap);
+
+    NtGdiBitBlt(hdc2, 0, 0, w, h, hdc, 0, 0, SRCCOPY, 0, 0);
+
+    UserSetClipboardData(CF_BITMAP, hbitmap, &scd);
+
+    UserReleaseDC(pWnd, hdc, FALSE);
+    UserReleaseDC(pWnd, hdc2, FALSE);
+
+    UserCloseClipboard();
+}
 
 /*
    Win32k counterpart of User DefWindowProc
@@ -374,6 +536,7 @@ IntDefWindowProc(
    LPARAM lParam,
    BOOL Ansi)
 {
+   PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
    LRESULT lResult = 0;
    USER_REFERENCE_ENTRY Ref;
 
@@ -381,12 +544,74 @@ IntDefWindowProc(
 
    switch (Msg)
    {
+      case WM_GETTEXTLENGTH:
+      {
+            PWSTR buf;
+            ULONG len;
+
+            if (Wnd != NULL && Wnd->strName.Length != 0)
+            {
+                buf = Wnd->strName.Buffer;
+                if (buf != NULL &&
+                    NT_SUCCESS(RtlUnicodeToMultiByteSize(&len,
+                                                         buf,
+                                                         Wnd->strName.Length)))
+                {
+                    lResult = (LRESULT) (Wnd->strName.Length / sizeof(WCHAR));
+                }
+            }
+            else lResult = 0L;
+
+            break;
+      }
+
+      case WM_GETTEXT: // FIXME: Handle Ansi
+      {
+            PWSTR buf = NULL;
+            PWSTR outbuf = (PWSTR)lParam;
+
+            if (Wnd != NULL && wParam != 0)
+            {
+                if (Wnd->strName.Buffer != NULL)
+                    buf = Wnd->strName.Buffer;
+                else
+                    outbuf[0] = L'\0';
+
+                if (buf != NULL)
+                {
+                    if (Wnd->strName.Length != 0)
+                    {
+                        lResult = min(Wnd->strName.Length / sizeof(WCHAR), wParam - 1);
+                        RtlCopyMemory(outbuf,
+                                      buf,
+                                      lResult * sizeof(WCHAR));
+                        outbuf[lResult] = L'\0';
+                    }
+                    else
+                        outbuf[0] = L'\0';
+                }
+            }
+            break;
+      }
+
+      case WM_SETTEXT: // FIXME: Handle Ansi
+      {
+            DefSetText(Wnd, (PCWSTR)lParam);
+
+            if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
+                UserPaintCaption(Wnd, DC_TEXT);
+            IntNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, Wnd, OBJID_WINDOW, CHILDID_SELF, 0);
+            lResult = 1;
+            break;
+      }
+
       case WM_SYSCOMMAND:
       {
-         ERR("hwnd %p WM_SYSCOMMAND %lx %lx\n", Wnd->head.h, wParam, lParam );
+         TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", Wnd->head.h, wParam, lParam );
          lResult = DefWndHandleSysCommand(Wnd, wParam, lParam);
          break;
       }
+
       case WM_SHOWWINDOW:
       {
          if ((Wnd->style & WS_VISIBLE) && wParam) break;
@@ -411,7 +636,6 @@ IntDefWindowProc(
          return IntClientShutdown(Wnd, wParam, lParam);
 
       case WM_APPCOMMAND:
-         ERR("WM_APPCOMMAND\n");
          if ( (Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
                Wnd != co_GetDesktopWindow(Wnd) )
          {
@@ -424,6 +648,241 @@ IntDefWindowProc(
          UserDerefObjectCo(Wnd->spwndParent);
          break;
 
+      case WM_KEYF1:
+      {
+         HELPINFO hi;
+         HMENU hMenu = UlongToHandle(Wnd->IDMenu);
+         PWND pwndActive = MENU_IsMenuActive();
+         hi.cbSize = sizeof(HELPINFO);
+         hi.MousePos = gpsi->ptCursor;
+         hi.iContextType = HELPINFO_MENUITEM;
+         hi.hItemHandle = pwndActive ? UserHMGetHandle(pwndActive) : UserHMGetHandle(Wnd);
+         hi.iCtrlId = (Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD ? IntMenuItemFromPoint(Wnd, hMenu, hi.MousePos) : 0;
+         hi.dwContextId = IntGetWindowContextHelpId(Wnd);
+
+         co_IntSendMessage( UserHMGetHandle(Wnd), WM_HELP, 0, (LPARAM)&hi );
+         break;
+      }
+
+      case WM_SETICON:
+      {
+         return DefWndSetIcon(Wnd, wParam, lParam);
+      }
+
+      case WM_GETICON:
+      {
+         return DefWndGetIcon(Wnd, wParam, lParam);
+      }
+
+      case WM_HELP:
+      {
+         PWND Parent = IntGetParent(Wnd);
+         co_IntSendMessage(UserHMGetHandle(Parent), Msg, wParam, lParam);
+         break;
+      }
+
+      case WM_LBUTTONDOWN:
+      case WM_RBUTTONDOWN:
+      case WM_MBUTTONDOWN:
+          pti->MessageQueue->QF_flags &= ~(QF_FMENUSTATUS|QF_FMENUSTATUSBREAK);
+          break;
+
+      case WM_NCLBUTTONDOWN:
+          return (NC_HandleNCLButtonDown( Wnd, wParam, lParam));
+
+      case WM_LBUTTONDBLCLK:
+          return (NC_HandleNCLButtonDblClk( Wnd, HTCLIENT, lParam));
+
+      case WM_NCLBUTTONDBLCLK:
+          return (NC_HandleNCLButtonDblClk( Wnd, wParam, lParam));
+
+      case WM_NCRBUTTONDOWN:
+          return NC_HandleNCRButtonDown( Wnd, wParam, lParam );
+
+      case WM_RBUTTONUP:
+      {
+            POINT Pt;
+
+            Pt.x = GET_X_LPARAM(lParam);
+            Pt.y = GET_Y_LPARAM(lParam);
+            IntClientToScreen(Wnd, &Pt);
+            lParam = MAKELPARAM(Pt.x, Pt.y);
+            co_IntSendMessage(UserHMGetHandle(Wnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(Wnd), lParam);
+            break;
+      }
+
+      case WM_NCRBUTTONUP:
+          /*
+           * FIXME : we must NOT send WM_CONTEXTMENU on a WM_NCRBUTTONUP (checked
+           * in Windows), but what _should_ we do? According to MSDN :
+           * "If it is appropriate to do so, the system sends the WM_SYSCOMMAND
+           * message to the window". When is it appropriate?
+           */
+           ERR("WM_NCRBUTTONUP\n");
+          break;
+
+      case WM_CONTEXTMENU:
+      {
+            if (Wnd->style & WS_CHILD)
+            {
+                co_IntSendMessage(UserHMGetHandle(IntGetParent(Wnd)), Msg, wParam, lParam);
+            }
+            else
+            {
+                POINT Pt;
+                LONG_PTR Style;
+                LONG HitCode;
+
+                Style = Wnd->style;
+
+                Pt.x = GET_X_LPARAM(lParam);
+                Pt.y = GET_Y_LPARAM(lParam);
+                if (Style & WS_CHILD)
+                {
+                    IntScreenToClient(IntGetParent(Wnd), &Pt);
+                }
+
+                HitCode = GetNCHitEx(Wnd, Pt);
+
+                if (HitCode == HTCAPTION || HitCode == HTSYSMENU)
+                {
+                    PMENU SystemMenu;
+                    UINT Flags;
+
+                    if((SystemMenu = IntGetSystemMenu(Wnd, FALSE)))
+                    {
+                      MENU_InitSysMenuPopup(SystemMenu, Wnd->style, Wnd->pcls->style, HitCode);
+
+                      if(HitCode == HTCAPTION)
+                        Flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON;
+                      else
+                        Flags = TPM_LEFTBUTTON;
+
+                      IntTrackPopupMenuEx(SystemMenu, Flags|TPM_SYSTEM_MENU, Pt.x, Pt.y, Wnd, NULL);
+                    }
+                }
+                if (HitCode == HTHSCROLL || HitCode == HTVSCROLL)
+                {
+                   WARN("Scroll Menu Not Supported\n");
+                }
+           }
+            break;
+      }
+
+      case WM_KEYDOWN:
+         if (wParam == VK_F10)
+         {
+            pti->MessageQueue->QF_flags |= QF_FF10STATUS;
+
+            if (UserGetKeyState(VK_SHIFT) & 0x8000)
+            {
+               co_IntSendMessage(UserHMGetHandle(Wnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(Wnd), MAKELPARAM(-1, -1));
+            }
+         }
+         break;
+
+      case WM_SYSKEYDOWN:
+      {
+            if (HIWORD(lParam) & KF_ALTDOWN)
+            {   /* Previous state, if the key was down before this message,
+                   this is a cheap way to ignore autorepeat keys. */
+                if ( !(HIWORD(lParam) & KF_REPEAT) )
+                {
+                   if ( ( wParam == VK_MENU  ||
+                          wParam == VK_LMENU ||
+                          wParam == VK_RMENU ) && !(pti->MessageQueue->QF_flags & QF_FMENUSTATUS)) //iMenuSysKey )
+                       pti->MessageQueue->QF_flags |= QF_FMENUSTATUS; //iMenuSysKey = 1;
+                   else
+                       pti->MessageQueue->QF_flags &= ~QF_FMENUSTATUS; //iMenuSysKey = 0;
+                }
+
+                pti->MessageQueue->QF_flags &= ~QF_FF10STATUS; //iF10Key = 0;
+
+                if (wParam == VK_F4) /* Try to close the window */
+                {
+                   PWND top = UserGetAncestor(Wnd, GA_ROOT);
+                   if (!(top->style & CS_NOCLOSE))
+                      UserPostMessage(UserHMGetHandle(top), WM_SYSCOMMAND, SC_CLOSE, 0);
+                }
+                else if (wParam == VK_SNAPSHOT) // Alt-VK_SNAPSHOT?
+                {
+                   PWND pwnd = Wnd;
+                   while (IntGetParent(pwnd) != NULL)
+                   {
+                       pwnd = IntGetParent(pwnd);
+                   }
+                   ERR("DefWndScreenshot\n");
+                   DefWndScreenshot(pwnd);
+                }
+                else if ( wParam == VK_ESCAPE || wParam == VK_TAB ) // Alt-Tab/ESC Alt-Shift-Tab/ESC
+                {
+                   WPARAM wParamTmp;
+                   HWND Active = UserGetActiveWindow(); // Noticed MDI problem.
+                   if (!Active)
+                   {
+                      FIXME("WM_SYSKEYDOWN VK_ESCAPE no active\n");
+                      break;
+                   }
+                   wParamTmp = UserGetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW;
+                   co_IntSendMessage( Active, WM_SYSCOMMAND, wParamTmp, wParam );
+                }
+            }
+            else if( wParam == VK_F10 )
+            {
+                if (UserGetKeyState(VK_SHIFT) & 0x8000)
+                    co_IntSendMessage( UserHMGetHandle(Wnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(Wnd), MAKELPARAM(-1, -1) );
+                pti->MessageQueue->QF_flags |= QF_FF10STATUS; //iF10Key = 1;
+            }
+            else if( wParam == VK_ESCAPE && (UserGetKeyState(VK_SHIFT) & 0x8000))
+                  co_IntSendMessage( UserHMGetHandle(Wnd), WM_SYSCOMMAND, SC_KEYMENU, ' ' );
+            break;
+      }
+
+      case WM_KEYUP:
+      case WM_SYSKEYUP:
+      {
+           /* Press and release F10 or ALT */
+            if (((wParam == VK_MENU || wParam == VK_LMENU || wParam == VK_RMENU)
+                 && (pti->MessageQueue->QF_flags & (QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) == QF_FMENUSTATUS /*iMenuSysKey*/) ||
+                 ((wParam == VK_F10) && pti->MessageQueue->QF_flags & QF_FF10STATUS /*iF10Key*/))
+                co_IntSendMessage( UserHMGetHandle(UserGetAncestor( Wnd, GA_ROOT )), WM_SYSCOMMAND, SC_KEYMENU, 0L );
+            pti->MessageQueue->QF_flags &= ~(QF_FMENUSTATUS|QF_FMENUSTATUSBREAK|QF_FF10STATUS); //iMenuSysKey = iF10Key = 0;
+            break;
+      }
+
+      case WM_SYSCHAR:
+      {
+            pti->MessageQueue->QF_flags &= ~(QF_FMENUSTATUS|QF_FMENUSTATUSBREAK); //iMenuSysKey = 0;
+            if (wParam == VK_RETURN && (Wnd->style & WS_MINIMIZE) != 0)
+            {
+                UserPostMessage( UserHMGetHandle(Wnd), WM_SYSCOMMAND, SC_RESTORE, 0L );
+                break;
+            }
+            if ((HIWORD(lParam) & KF_ALTDOWN) && wParam)
+            {
+                if (wParam == VK_TAB || wParam == VK_ESCAPE) break;
+                if (wParam == VK_SPACE && Wnd->style & WS_CHILD)
+                    co_IntSendMessage( UserHMGetHandle(IntGetParent(Wnd)), Msg, wParam, lParam );
+                else
+                    co_IntSendMessage( UserHMGetHandle(Wnd), WM_SYSCOMMAND, SC_KEYMENU, wParam );
+            }
+            else /* check for Ctrl-Esc */
+                if (wParam != VK_ESCAPE) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0);
+            break;
+      }
+
+      case WM_CANCELMODE:
+      {
+         pti->MessageQueue->QF_flags &= ~(QF_FMENUSTATUS|QF_FMENUSTATUSBREAK);
+
+         MENU_EndMenu( Wnd );
+         if (IntGetCaptureWindow() == UserHMGetHandle(Wnd))
+         {
+            IntReleaseCapture();
+         }
+         break;
+      }
+
       case WM_CLOSE:
          co_UserDestroyWindow(Wnd);
          break;
@@ -457,6 +916,18 @@ IntDefWindowProc(
          return DefWndHandleSetCursor(Wnd, wParam, lParam);
       }
 
+      case WM_MOUSEACTIVATE:
+         if (Wnd->style & WS_CHILD)
+         {
+             LONG Ret;
+             HWND hwndParent;
+             PWND pwndParent = IntGetParent(Wnd);
+             hwndParent = pwndParent ? UserHMGetHandle(pwndParent) : NULL;
+             if (hwndParent) Ret = co_IntSendMessage(hwndParent, WM_MOUSEACTIVATE, wParam, lParam);
+             if (Ret) return (Ret);
+         }
+         return ( (HIWORD(lParam) == WM_LBUTTONDOWN && LOWORD(lParam) == HTCAPTION) ? MA_NOACTIVATE : MA_ACTIVATE );
+
       case WM_ACTIVATE:
        /* The default action in Windows is to set the keyboard focus to
         * the window, if it's being activated and not minimized */
@@ -523,6 +994,18 @@ IntDefWindowProc(
          return (0);
       }
 
+      case WM_SYSCOLORCHANGE:
+      {
+         /* force to redraw non-client area */
+         UserPaintCaption(Wnd, DC_NC);
+         /* Use InvalidateRect to redraw client area, enable
+          * erase to redraw all subcontrols otherwise send the
+          * WM_SYSCOLORCHANGE to child windows/controls is required
+          */
+         co_UserRedrawWindow( Wnd, NULL, NULL, RDW_ALLCHILDREN|RDW_INVALIDATE|RDW_ERASE);
+         return (0);
+      }
+
       case WM_PAINTICON:
       case WM_PAINT:
       {
@@ -548,7 +1031,9 @@ IntDefWindowProc(
                  IntGetClientRect(Wnd, &ClientRect);
                  x = (ClientRect.right - ClientRect.left - UserGetSystemMetrics(SM_CXICON)) / 2;
                  y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2;
+                 UserReferenceObject(Wnd->pcls->spicn);
                  UserDrawIconEx(hDC, x, y, Wnd->pcls->spicn, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
+                 UserDereferenceObject(Wnd->pcls->spicn);
              }
 
              IntEndPaint(Wnd, &Ps);
@@ -578,7 +1063,6 @@ IntDefWindowProc(
       }
 
       case WM_SETREDRAW:
-          ERR("WM_SETREDRAW\n");
           if (wParam)
           {
              if (!(Wnd->style & WS_VISIBLE))
@@ -607,6 +1091,53 @@ IntDefWindowProc(
           return (DefWndHandleWindowPosChanged(Wnd, (WINDOWPOS*)lParam));
       }
 
+      case WM_NCCALCSIZE:
+      {
+         return NC_HandleNCCalcSize( Wnd, wParam, (RECTL *)lParam );
+      }
+
+      case WM_NCACTIVATE:
+      {
+          return NC_HandleNCActivate( Wnd, wParam, lParam );
+      }
+
+      //
+      // NC Paint mode.
+      //
+      case WM_NCPAINT:
+      {
+          HDC hDC = UserGetDCEx(Wnd, (HRGN)wParam, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
+          Wnd->state |= WNDS_FORCEMENUDRAW;
+          NC_DoNCPaint(Wnd, hDC, -1);
+          Wnd->state &= ~WNDS_FORCEMENUDRAW;
+          UserReleaseDC(Wnd, hDC, FALSE);
+          return 0;
+      }
+      //
+      //  Draw Caption mode.
+      //
+      //  wParam are DC_* flags.
+      //
+      case WM_NCUAHDRAWCAPTION:
+      {
+          HDC hDC = UserGetDCEx(Wnd, NULL, DCX_WINDOW|DCX_USESTYLE);
+          TRACE("WM_NCUAHDRAWCAPTION: wParam DC_ flags %08x\n",wParam);
+          UserDrawCaptionBar(Wnd, hDC, wParam|DC_FRAME); // Include DC_FRAME to comp for drawing glich.
+          UserReleaseDC(Wnd, hDC, FALSE);
+          return 0;
+      }
+      //
+      //  Draw Frame mode.
+      //
+      //  wParam is HDC, lParam are DC_ACTIVE and or DC_REDRAWHUNGWND.
+      //
+      case WM_NCUAHDRAWFRAME:
+      {
+          TRACE("WM_NCUAHDRAWFRAME: wParam hDC %p lParam DC_ flags %08x\n",wParam,lParam);
+          NC_DoNCPaint(Wnd, (HDC)wParam, lParam|DC_NC);
+          return 0;
+      }
+
       /* ReactOS only. */
       case WM_CBT:
       {
index cbd6b20..a1eb591 100644 (file)
@@ -664,6 +664,7 @@ DesktopWindowProc(PWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lRe
       case WM_SYSCOLORCHANGE:
          co_UserRedrawWindow(Wnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
          return TRUE;
+
       case WM_SETCURSOR:
       {
           PCURICON_OBJECT pcurOld, pcurNew;
@@ -691,8 +692,11 @@ DesktopWindowProc(PWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lRe
               HDESK hdesk = IntGetDesktopObjectHandle(gpdeskInputDesktop);
               IntSetThreadDesktop(hdesk, FALSE);
           }
+          break;
       }
-
+      default:
+          TRACE("DWP calling IDWP Msg %d\n",Msg);
+          *lResult = IntDefWindowProc(Wnd, Msg, wParam, lParam, FALSE);
    }
    return TRUE; /* We are done. Do not do any callbacks to user mode */
 }
@@ -711,6 +715,9 @@ UserMessageWindowProc(PWND pwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT
     case WM_DESTROY:
         pwnd->fnid |= FNID_DESTROY;
         break;
+    default:
+        ERR("UMWP calling IDWP\n");
+        *lResult = IntDefWindowProc(pwnd, Msg, wParam, lParam, FALSE);
     }
 
     return TRUE; /* We are done. Do not do any callbacks to user mode */
index c663185..bd72837 100644 (file)
@@ -948,6 +948,14 @@ BOOL FASTCALL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
     WCHAR Symbol;
     switch(uFlags & 0xff)
     {
+        case DFCS_MENUARROWUP:
+            Symbol = '5';
+            break;
+
+        case DFCS_MENUARROWDOWN:
+            Symbol = '6';
+            break;
+
         case DFCS_MENUARROW:
             Symbol = '8';
             break;
@@ -980,8 +988,6 @@ BOOL FASTCALL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
     hFont = GreCreateFontIndirectW(&lf);
     /* save font */
     hOldFont = NtGdiSelectFont(dc, hFont);
-    // FIXME selecting color doesn't work
-#if 0
     if(uFlags & DFCS_INACTIVE)
     {
         /* draw shadow */
@@ -989,7 +995,6 @@ BOOL FASTCALL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
         GreTextOutW(dc, r->left + 1, r->top + 1, &Symbol, 1);
     }
     IntGdiSetTextColor(dc, IntGetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
-#endif
     /* draw selected symbol */
     GreTextOutW(dc, r->left, r->top, &Symbol, 1);
     /* restore previous settings */
@@ -1005,6 +1010,25 @@ BOOL FASTCALL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
 //
 
 
+INT WINAPI
+FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
+{
+    HBRUSH oldbrush;
+    RECT r = *lprc;
+
+    if ((r.right <= r.left) || (r.bottom <= r.top)) return 0;
+    if (!(oldbrush = NtGdiSelectBrush(hDC, hbr))) return 0;
+
+    NtGdiPatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
+    NtGdiPatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
+    NtGdiPatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
+    NtGdiPatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
+
+    NtGdiSelectBrush(hDC, oldbrush);
+    return TRUE;
+}
+
+
 INT WINAPI
 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
 {
index ada0f2c..ec5c6fc 100644 (file)
@@ -66,7 +66,7 @@ co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
                     (LPARAM)hWnd);
 
          if (WndPrev)
-            WndPrev->state &= ~WNDS_ACTIVEFRAME;
+            WndPrev->state &= ~(WNDS_ACTIVEFRAME|WNDS_HASCAPTION);
       }
       else
       {
@@ -700,7 +700,7 @@ co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
    }
 
    // FIXME: Used in the menu loop!!!
-   //ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
+   ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
 
    //ERR("co_IntSetActiveWindow Exit\n");
    if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
@@ -946,7 +946,11 @@ co_UserSetCapture(HWND hWnd)
    if (Window)
       IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
 
-   if (hWndPrev && hWndPrev != hWnd)
+   //
+   // Only send the message if we have a previous Window!
+   // Fix msg_menu tracking popup menu and win test_capture_4!!!!
+   //
+   if (hWndPrev)
    {
       if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
 
index b5452cf..ab0dcfc 100644 (file)
@@ -936,7 +936,7 @@ ProcessKeyEvent(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD d
             /* FIXME: Set KF_DLGMODE and KF_MENUMODE when needed */
             if (pFocusQueue->QF_flags & QF_DIALOGACTIVE)
                 Msg.lParam |= KF_DLGMODE << 16;
-            if (pFocusQueue->MenuOwner) // pFocusQueue->MenuState) // MenuState needs a start flag...
+            if (pFocusQueue->MenuOwner) // pti->pMenuState->fMenuStarted
                 Msg.lParam |= KF_MENUMODE << 16;
         }
 
@@ -951,7 +951,6 @@ ProcessKeyEvent(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD d
         if (!Wnd) {ERR("Window is NULL\n");}
         MsqPostMessage(pti, &Msg, TRUE, QS_KEY, 0, dwExtraInfo);
     }
-
     return TRUE;
 }
 
index 6ce59d0..d672ef3 100644 (file)
@@ -11,7 +11,29 @@ DBG_DEFAULT_CHANNEL(UserMenu);
 
 /* INTERNAL ******************************************************************/
 
-BOOL FASTCALL IntSetMenuItemInfo(PMENU, PITEM, PROSMENUITEMINFO, PUNICODE_STRING);
+HFONT ghMenuFont = NULL;
+HFONT ghMenuFontBold = NULL;
+static SIZE MenuCharSize;
+
+/* Use global popup window because there's no way 2 menus can
+ * be tracked at the same time.  */
+static HWND top_popup = NULL;
+static HMENU top_popup_hmenu = NULL;
+
+BOOL fInsideMenuLoop = FALSE;
+BOOL fInEndMenu = FALSE;
+
+/* internal popup menu window messages */
+
+#define MM_SETMENUHANDLE        (WM_USER + 0)
+#define MM_GETMENUHANDLE        (WM_USER + 1)
+
+/* internal flags for menu tracking */
+
+#define TF_ENDMENU              0x10000
+#define TF_SUSPENDPOPUP         0x20000
+#define TF_SKIPREMOVE           0x40000
+
 
 /* maximum allowed depth of any branch in the menu tree.
  * This value is slightly larger than in windows (25) to
@@ -33,10 +55,50 @@ BOOL FASTCALL IntSetMenuItemInfo(PMENU, PITEM, PROSMENUITEMINFO, PUNICODE_STRING
 
 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
 
+#define IS_SYSTEM_MENU(MenuInfo)  \
+       (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
+
+#define IS_SYSTEM_POPUP(MenuInfo) \
+       (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
+
+#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
+
+#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
+#define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
+
 /* Maximum number of menu items a menu can contain */
 #define MAX_MENU_ITEMS (0x4000)
 #define MAX_GOINTOSUBMENU (0x10)
 
+/* Space between 2 columns */
+#define MENU_COL_SPACE 4
+
+/*  top and bottom margins for popup menus */
+#define MENU_TOP_MARGIN 2 //3
+#define MENU_BOTTOM_MARGIN 2
+
+#define MENU_ITEM_HBMP_SPACE (5)
+#define MENU_BAR_ITEMS_SPACE (12)
+#define SEPARATOR_HEIGHT (5)
+#define MENU_TAB_SPACE (8)
+
+typedef struct
+{
+  UINT  TrackFlags;
+  PMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
+  PMENU TopMenu;     /* initial menu */
+  PWND  OwnerWnd;    /* where notifications are sent */
+  POINT Pt;
+} MTRACKER;
+
+/* Internal MenuTrackMenu() flags */
+#define TPM_INTERNAL            0xF0000000
+#define TPM_BUTTONDOWN          0x40000000              /* menu was clicked before tracking */
+#define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
+
+#define ITEM_PREV               -1
+#define ITEM_NEXT                1
+
 #define UpdateMenuItemState(state, change) \
 {\
   if((change) & MF_GRAYED) { \
@@ -147,9 +209,12 @@ PMENU FASTCALL VerifyMenu(PMENU pMenu)
 {
    HMENU hMenu;
    PITEM pItem;
+   ULONG Error;
    UINT i;
    if (!pMenu) return NULL;
 
+   Error = EngGetLastError();
+
    _SEH2_TRY
    {
       hMenu = UserHMGetHandle(pMenu);
@@ -163,6 +228,7 @@ PMENU FASTCALL VerifyMenu(PMENU pMenu)
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
       ERR("Run away LOOP!\n");
+      EngSetLastError(Error);
       _SEH2_YIELD(return NULL);
    }
    _SEH2_END
@@ -170,12 +236,34 @@ PMENU FASTCALL VerifyMenu(PMENU pMenu)
    if ( UserObjectInDestroy(hMenu))
    {
       ERR("Menu is marked for destruction!\n");
-      return NULL;
+      pMenu = NULL;
    }
-
+   EngSetLastError(Error);
    return pMenu;
 }
 
+PMENU WINAPI
+IntGetMenu(HWND hWnd)
+{
+       PWND Wnd = ValidateHwndNoErr(hWnd);
+
+       if (!Wnd)
+               return NULL;
+
+       return UserGetMenuObject(UlongToHandle(Wnd->IDMenu));
+}
+
+PMENU get_win_sys_menu( HWND hwnd )   
+{
+   PMENU ret = 0;
+   WND *win = ValidateHwndNoErr( hwnd );        
+   if (win)
+   {
+      ret = UserGetMenuObject(win->SystemMenu);
+   }
+   return ret;
+}
+
 BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse)
 {
     PMENU SubMenu;
@@ -228,6 +316,7 @@ IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
    if(Menu)
    {
       PWND Window;
+      ULONG Error;
 
       /* Remove all menu items */
       IntDestroyMenu( Menu, bRecurse);
@@ -237,10 +326,10 @@ IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
          BOOL ret;
          if (Menu->hWnd)
          {
-            Window = UserGetWindowObject(Menu->hWnd);
+            Window = ValidateHwndNoErr(Menu->hWnd);
             if (Window)
             {
-               Window->IDMenu = 0;
+               //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
 
                /* DestroyMenu should not destroy system menu popup owner */
                if ((Menu->fFlags & (MNF_POPUP | MNF_SYSSUBMENU)) == MNF_POPUP)
@@ -260,8 +349,13 @@ IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
          ret = UserDeleteObject(Menu->head.h, TYPE_MENU);
          if (!ret)
          {  // Make sure it is really dead or just marked for deletion.
+            Error = EngGetLastError();
             ret = UserObjectInDestroy(Menu->head.h);
-            if (ret && EngGetLastError() == ERROR_INVALID_HANDLE) ret = FALSE;
+            if (ret && EngGetLastError() == ERROR_INVALID_HANDLE)
+            {
+               EngSetLastError(Error);
+               ret = FALSE;
+            }
          }  // See test_subpopup_locked_by_menu tests....
          return ret;
       }
@@ -269,6 +363,47 @@ IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
    return FALSE;
 }
 
+BOOL
+MenuInit(VOID)
+{
+  NONCLIENTMETRICSW ncm;
+
+  /* get the menu font */
+  if (!ghMenuFont || !ghMenuFontBold)
+  {
+    ncm.cbSize = sizeof(ncm);
+    if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+    {
+      ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
+      return FALSE;
+    }
+
+    ghMenuFont = GreCreateFontIndirectW(&ncm.lfMenuFont);
+    if (ghMenuFont == NULL)
+    {
+      ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
+      return FALSE;
+    }
+    ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
+    ghMenuFontBold = GreCreateFontIndirectW(&ncm.lfMenuFont);
+    if (ghMenuFontBold == NULL)
+    {
+      ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
+      GreDeleteObject(ghMenuFont);
+      ghMenuFont = NULL;
+      return FALSE;
+    }
+    
+    GreSetObjectOwner(ghMenuFont, GDI_OBJ_HMGR_PUBLIC);
+    GreSetObjectOwner(ghMenuFontBold, GDI_OBJ_HMGR_PUBLIC);
+
+    co_IntSetupOBM();
+  }
+
+  return TRUE;
+}
+
+
 /**********************************************************************
  *             MENU_depth
  *
@@ -299,6 +434,78 @@ int FASTCALL MENU_depth( PMENU pmenu, int depth)
     return subdepth;
 }
 
+
+/******************************************************************************
+ *
+ *   UINT MenuGetStartOfNextColumn(
+ *     PMENU Menu)
+ *
+ *****************************************************************************/
+
+static UINT  MENU_GetStartOfNextColumn(
+    PMENU  menu )
+{
+    PITEM pItem;
+    UINT i;
+
+    if(!menu)
+       return NO_SELECTED_ITEM;
+
+    i = menu->iItem + 1;
+    if( i == NO_SELECTED_ITEM )
+       return i;
+
+    pItem = menu->rgItems;
+    if (!pItem) return NO_SELECTED_ITEM;
+    for( ; i < menu->cItems; ++i ) {
+       if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
+           return i;
+    }
+
+    return NO_SELECTED_ITEM;
+}
+
+/******************************************************************************
+ *
+ *   UINT MenuGetStartOfPrevColumn(
+ *     PMENU Menu)
+ *
+ *****************************************************************************/
+static UINT  MENU_GetStartOfPrevColumn(
+    PMENU  menu )
+{
+    UINT  i;
+    PITEM pItem;
+
+    if( !menu )
+       return NO_SELECTED_ITEM;
+
+    if( menu->iItem == 0 || menu->iItem == NO_SELECTED_ITEM )
+       return NO_SELECTED_ITEM;
+
+    pItem = menu->rgItems;
+    if (!pItem) return NO_SELECTED_ITEM;
+
+    /* Find the start of the column */
+
+    for(i = menu->iItem; i != 0 &&
+        !(pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK));
+       --i); /* empty */
+
+    if(i == 0)
+       return NO_SELECTED_ITEM;
+
+    for(--i; i != 0; --i) {
+       if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
+           break;
+    }
+
+    TRACE("ret %d.\n", i );
+
+    return i;
+}
+
 /***********************************************************************
  *           MENU_FindItem
  *
@@ -355,6 +562,44 @@ PITEM FASTCALL MENU_FindItem( PMENU *pmenu, UINT *nPos, UINT wFlags )
     return fallback;
 }
 
+/***********************************************************************
+ *           MenuFindSubMenu
+ *
+ * Find a Sub menu. Return the position of the submenu, and modifies
+ * *hmenu in case it is found in another sub-menu.
+ * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
+ */
+static UINT FASTCALL MENU_FindSubMenu(PMENU *menu, PMENU SubTarget )
+{
+    UINT i;
+    PITEM item;
+
+    item = ((PMENU)*menu)->rgItems;
+    for (i = 0; i < ((PMENU)*menu)->cItems; i++, item++)
+    {
+        if (!item->spSubMenu)
+           continue;
+        else
+        {
+           if (item->spSubMenu == SubTarget)
+           {
+              return i;
+           }
+           else 
+           {
+              PMENU pSubMenu = item->spSubMenu;
+              UINT pos = MENU_FindSubMenu( &pSubMenu, SubTarget );
+              if (pos != NO_SELECTED_ITEM)
+              {
+                  *menu = pSubMenu;
+                  return pos;
+              }
+           }
+        }
+    }
+    return NO_SELECTED_ITEM;
+}
+
 BOOL FASTCALL
 IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
 {
@@ -990,12 +1235,15 @@ IntEnableMenuItem(PMENU MenuObject, UINT uIDEnableItem, UINT uEnable)
         case SC_SIZE:
        if (MenuObject->fFlags & MNF_SYSSUBMENU && MenuObject->spwndNotify != 0)
        {
-            RECTL rc = MenuObject->spwndNotify->rcWindow;
+            //RECTL rc = MenuObject->spwndNotify->rcWindow;
 
             /* Refresh the frame to reflect the change */
-            IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
-            rc.bottom = 0;
-            co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
+            //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
+            //rc.bottom = 0;
+            //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
+
+            // Allow UxTheme!
+            UserPaintCaption(MenuObject->spwndNotify, DC_BUTTONS);
        }
        default:
            break;
@@ -1014,9 +1262,3243 @@ IntCheckMenuItem(PMENU MenuObject, UINT uIDCheckItem, UINT uCheck)
 
    res = (DWORD)(MenuItem->fState & MF_CHECKED);
 
-   MenuItem->fState ^= (res ^ uCheck) & MF_CHECKED;
+   MenuItem->fState ^= (res ^ uCheck) & MF_CHECKED;
+
+   return res;
+}
+
+BOOL FASTCALL
+UserSetMenuDefaultItem(PMENU MenuObject, UINT uItem, UINT fByPos)
+{
+   UINT i;
+   PITEM MenuItem = MenuObject->rgItems;
+
+   if (!MenuItem) return FALSE;
+
+   /* reset all default-item flags */
+   for (i = 0; i < MenuObject->cItems; i++, MenuItem++)
+   {
+       MenuItem->fState &= ~MFS_DEFAULT;
+   }
+
+   /* no default item */
+   if(uItem == (UINT)-1)
+   {
+      return TRUE;
+   }
+   MenuItem = MenuObject->rgItems;
+   if ( fByPos )
+   {
+      if ( uItem >= MenuObject->cItems ) return FALSE;
+         MenuItem[uItem].fState |= MFS_DEFAULT;
+      return TRUE;
+   }
+   else
+   {
+      for (i = 0; i < MenuObject->cItems; i++, MenuItem++)
+      {
+          if (MenuItem->wID == uItem)
+          {
+             MenuItem->fState |= MFS_DEFAULT;
+             return TRUE;
+          }
+      }
+
+   }
+   return FALSE;
+}
+
+UINT FASTCALL
+IntGetMenuDefaultItem(PMENU MenuObject, UINT fByPos, UINT gmdiFlags, DWORD *gismc)
+{
+   UINT i = 0;
+   PITEM MenuItem = MenuObject->rgItems;
+
+   /* empty menu */
+   if (!MenuItem) return -1;
+
+   while ( !( MenuItem->fState & MFS_DEFAULT ) )
+   {
+      i++; MenuItem++;
+      if  (i >= MenuObject->cItems ) return -1;
+   }
+
+   /* default: don't return disabled items */
+   if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (MenuItem->fState & MFS_DISABLED )) return -1;
+
+   /* search rekursiv when needed */
+   if ( (MenuItem->fType & MF_POPUP) && (gmdiFlags & GMDI_GOINTOPOPUPS) && MenuItem->spSubMenu)
+   {
+      UINT ret;
+      (*gismc)++;
+      ret = IntGetMenuDefaultItem( MenuItem->spSubMenu, fByPos, gmdiFlags, gismc );
+      (*gismc)--;
+      if ( -1 != ret ) return ret;
+
+      /* when item not found in submenu, return the popup item */
+   }
+   return ( fByPos ) ? i : MenuItem->wID;
+}
+
+PMENU
+FASTCALL
+co_IntGetSubMenu(
+  PMENU pMenu,
+  int nPos)
+{
+  PITEM pItem;
+  if (!(pItem = MENU_FindItem( &pMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
+  return pItem->spSubMenu;
+}
+
+/***********************************************************************
+ *           MenuInitSysMenuPopup
+ *
+ * Grey the appropriate items in System menu.
+ */
+void FASTCALL MENU_InitSysMenuPopup(PMENU menu, DWORD style, DWORD clsStyle, LONG HitTest )
+{
+    BOOL gray;
+    UINT DefItem;
+
+    gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
+    IntEnableMenuItem( menu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = ((style & WS_MAXIMIZE) != 0);
+    IntEnableMenuItem( menu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
+    IntEnableMenuItem( menu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
+    IntEnableMenuItem( menu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
+    IntEnableMenuItem( menu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
+    gray = (clsStyle & CS_NOCLOSE) != 0;
+
+    /* The menu item must keep its state if it's disabled */
+    if(gray)
+        IntEnableMenuItem( menu, SC_CLOSE, MF_GRAYED);
+
+    /* Set default menu item */
+    if(style & WS_MINIMIZE) DefItem = SC_RESTORE;
+    else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
+    else DefItem = SC_CLOSE;
+
+    UserSetMenuDefaultItem(menu, DefItem, MF_BYCOMMAND);
+}
+
+
+/***********************************************************************
+ *           MenuDrawPopupGlyph
+ *
+ * Draws popup magic glyphs (can be found in system menu).
+ */
+static void FASTCALL
+MENU_DrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite)
+{
+  LOGFONTW lf;
+  HFONT hFont, hOldFont;
+  COLORREF clrsave;
+  INT bkmode;
+  WCHAR symbol;
+  switch (popupMagic)
+  {
+  case (INT_PTR) HBMMENU_POPUP_RESTORE:
+    symbol = '2';
+    break;
+  case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+    symbol = '0';
+    break;
+  case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+    symbol = '1';
+    break;
+  case (INT_PTR) HBMMENU_POPUP_CLOSE:
+    symbol = 'r';
+    break;
+  default:
+    ERR("Invalid popup magic bitmap %d\n", (int)popupMagic);
+    return;
+  }
+  RtlZeroMemory(&lf, sizeof(LOGFONTW));
+  RECTL_vInflateRect(r, -2, -2);
+  lf.lfHeight = r->bottom - r->top;
+  lf.lfWidth = 0;
+  lf.lfWeight = FW_NORMAL;
+  lf.lfCharSet = DEFAULT_CHARSET;
+  RtlCopyMemory(lf.lfFaceName, L"Marlett", sizeof(L"Marlett"));
+  hFont = GreCreateFontIndirectW(&lf);
+  /* save font and text color */
+  hOldFont = NtGdiSelectFont(dc, hFont);
+  clrsave = GreGetTextColor(dc);
+  bkmode = GreGetBkMode(dc);
+  /* set color and drawing mode */
+  IntGdiSetBkMode(dc, TRANSPARENT);
+  if (inactive)
+  {
+    /* draw shadow */
+    if (!hilite)
+    {
+      IntGdiSetTextColor(dc, IntGetSysColor(COLOR_HIGHLIGHTTEXT));
+      GreTextOutW(dc, r->left + 1, r->top + 1, &symbol, 1);
+    }
+  }
+  IntGdiSetTextColor(dc, IntGetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)));
+  /* draw selected symbol */
+  GreTextOutW(dc, r->left, r->top, &symbol, 1);
+  /* restore previous settings */
+  IntGdiSetTextColor(dc, clrsave);
+  NtGdiSelectFont(dc, hOldFont);
+  IntGdiSetBkMode(dc, bkmode);
+  GreDeleteObject(hFont);
+}
+
+/***********************************************************************
+ *           MENU_AdjustMenuItemRect
+ *
+ * Adjust menu item rectangle according to scrolling state.
+ */
+VOID FASTCALL
+MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect)
+{
+    if (menu->dwArrowsOn)
+    {
+        UINT arrow_bitmap_height;
+        arrow_bitmap_height = gpsi->oembmi[OBI_UPARROW].cy; ///// Menu up arrow! OBM_UPARROW
+        rect->top += arrow_bitmap_height - menu->iTop;
+        rect->bottom += arrow_bitmap_height - menu->iTop;
+    }
+}
+
+/***********************************************************************
+ *           MENU_FindItemByCoords
+ *
+ * Find the item at the specified coordinates (screen coords). Does
+ * not work for child windows and therefore should not be called for
+ * an arbitrary system menu.
+ */
+static ITEM *MENU_FindItemByCoords( MENU *menu, POINT pt, UINT *pos )
+{
+    ITEM *item;
+    UINT i;
+    RECT rect;
+    PWND pWnd = ValidateHwndNoErr(menu->hWnd);
+
+    if (!IntGetWindowRect(pWnd, &rect)) return NULL;
+    if (pWnd->ExStyle & WS_EX_LAYOUTRTL)
+       pt.x = rect.right - 1 - pt.x;
+    else
+       pt.x -= rect.left;
+    pt.y -= rect.top;
+    item = menu->rgItems;
+    for (i = 0; i < menu->cItems; i++, item++)
+    {
+        //rect = item->rect;
+        rect.left   = item->xItem;
+        rect.top    = item->yItem; 
+        rect.right  = item->cxItem; // Do this for now......
+        rect.bottom = item->cyItem;
+
+        MENU_AdjustMenuItemRect(menu, &rect);
+       if (RECTL_bPointInRect(&rect, pt.x, pt.y))
+       {
+           if (pos) *pos = i;
+           return item;
+       }
+    }
+    return NULL;
+}
+
+INT FASTCALL IntMenuItemFromPoint(PWND pWnd, HMENU hMenu, POINT ptScreen)
+{
+    MENU *menu = UserGetMenuObject(hMenu);
+    UINT pos;
+
+    /*FIXME: Do we have to handle hWnd here? */
+    if (!menu) return -1;
+    if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
+    return pos;
+}
+
+/***********************************************************************
+ *           MenuFindItemByKey
+ *
+ * Find the menu item selected by a key press.
+ * Return item id, -1 if none, -2 if we should close the menu.
+ */
+static UINT FASTCALL MENU_FindItemByKey(PWND WndOwner, PMENU menu,
+                  WCHAR Key, BOOL ForceMenuChar)
+{
+  LRESULT MenuChar;
+  WORD Flags = 0;
+
+  TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, menu );
+
+  if (!menu || !VerifyMenu(menu))
+     menu = co_IntGetSubMenu( UserGetMenuObject(WndOwner->SystemMenu), 0 );
+  if (menu)
+  {
+     ITEM *item = menu->rgItems;
+
+     if ( !ForceMenuChar )
+     {
+        UINT i;
+        BOOL cjk = UserGetSystemMetrics( SM_DBCSENABLED );
+
+        for (i = 0; i < menu->cItems; i++, item++)
+        {
+           LPWSTR text = item->Xlpstr;
+           if( text)
+           {
+              const WCHAR *p = text - 2;
+              do
+              {
+                 const WCHAR *q = p + 2;
+                 p = wcschr (q, '&');
+                 if (!p && cjk) p = wcschr (q, '\036'); /* Japanese Win16 */
+              }
+              while (p != NULL && p [1] == '&');
+              if (p && (towupper(p[1]) == towupper(Key))) return i;
+           }
+        }
+     }
+
+     Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0;
+     Flags |= menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0;
+
+     MenuChar = co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MENUCHAR,
+                              MAKEWPARAM(Key, Flags), (LPARAM) UserHMGetHandle(menu));
+     if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
+     if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
+  }
+  return (UINT)(-1);
+}
+
+/***********************************************************************
+ *           MenuGetBitmapItemSize
+ *
+ * Get the size of a bitmap item.
+ */
+static void FASTCALL MENU_GetBitmapItemSize(PITEM lpitem, SIZE *size, PWND WndOwner)
+{
+    BITMAP bm;
+    HBITMAP bmp = lpitem->hbmp;
+
+    size->cx = size->cy = 0;
+
+    /* check if there is a magic menu item associated with this item */
+    if (IS_MAGIC_BITMAP(bmp))
+    {
+      switch((INT_PTR) bmp)
+        {
+            case (INT_PTR)HBMMENU_CALLBACK:
+            {
+                MEASUREITEMSTRUCT measItem;
+                measItem.CtlType = ODT_MENU;
+                measItem.CtlID = 0;
+                measItem.itemID = lpitem->wID;
+                measItem.itemWidth  = lpitem->cxItem - lpitem->xItem; //lpitem->Rect.right  - lpitem->Rect.left;
+                measItem.itemHeight = lpitem->cyItem - lpitem->yItem; //lpitem->Rect.bottom - lpitem->Rect.top;
+                measItem.itemData = lpitem->dwItemData;
+                co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MEASUREITEM, 0, (LPARAM)&measItem);
+                size->cx = measItem.itemWidth;
+                size->cy = measItem.itemHeight;
+                TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem.itemHeight,measItem.itemWidth);
+                return;
+            }
+            break;
+
+          case (INT_PTR) HBMMENU_SYSTEM:
+            if (lpitem->dwItemData)
+              {
+                bmp = (HBITMAP) lpitem->dwItemData;
+                break;
+              }
+            /* fall through */
+          case (INT_PTR) HBMMENU_MBAR_RESTORE:
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+          case (INT_PTR) HBMMENU_MBAR_CLOSE:
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+          case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+          case (INT_PTR) HBMMENU_POPUP_CLOSE:
+          case (INT_PTR) HBMMENU_POPUP_RESTORE:
+          case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+          case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+            /* FIXME: Why we need to subtract these magic values? */
+            /* to make them smaller than the menu bar? */
+            size->cx = UserGetSystemMetrics(SM_CXSIZE) - 2;
+            size->cy = UserGetSystemMetrics(SM_CYSIZE) - 4;
+            return;
+        }
+    }
+
+    if (GreGetObject(bmp, sizeof(BITMAP), &bm))
+    {
+        size->cx = bm.bmWidth;
+        size->cy = bm.bmHeight;
+    }
+}
+
+/***********************************************************************
+ *           MenuDrawBitmapItem
+ *
+ * Draw a bitmap item.
+ */
+static void FASTCALL MENU_DrawBitmapItem(HDC hdc, PITEM lpitem, const RECT *rect,
+                    PMENU Menu, PWND WndOwner, UINT odaction, BOOL MenuBar)
+{
+    BITMAP bm;
+    DWORD rop;
+    HDC hdcMem;
+    HBITMAP bmp;
+    int w = rect->right - rect->left;
+    int h = rect->bottom - rect->top;
+    int bmp_xoffset = 0;
+    int left, top;
+    HBITMAP hbmToDraw = lpitem->hbmp;
+    bmp = hbmToDraw;
+
+    /* Check if there is a magic menu item associated with this item */
+    if (IS_MAGIC_BITMAP(hbmToDraw))
+    {
+        UINT flags = 0;
+        RECT r;
+
+      r = *rect;
+      switch ((INT_PTR)hbmToDraw)
+      {
+        case (INT_PTR)HBMMENU_SYSTEM:
+            if (lpitem->dwItemData)
+            {
+                if (ValidateHwndNoErr((HWND)lpitem->dwItemData))
+                {
+                   ERR("Get Item Data from this Window!!!\n");
+                }
+
+                ERR("Draw Bitmap\n");
+                bmp = (HBITMAP)lpitem->dwItemData;
+                if (!GreGetObject( bmp, sizeof(bm), &bm )) return;
+            }
+            else
+            {
+                PCURICON_OBJECT pIcon = NULL;
+                //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
+                //bmp = BmpSysMenu;
+                //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
+                /* only use right half of the bitmap */
+                //bmp_xoffset = bm.bmWidth / 2;
+                //bm.bmWidth -= bmp_xoffset;
+                if (WndOwner)
+                {
+                    pIcon = NC_IconForWindow(WndOwner);
+                    // FIXME: NC_IconForWindow should reference it for us */
+                    if (pIcon) UserReferenceObject(pIcon);
+                }
+                ERR("Draw ICON\n");
+                if (pIcon)
+                {
+                   LONG cx = UserGetSystemMetrics(SM_CXSMICON);
+                   LONG cy = UserGetSystemMetrics(SM_CYSMICON);
+                   LONG x = rect->left - cx/2 + 1 + (rect->bottom - rect->top)/2; // this is really what Window does
+                   LONG y = (rect->top + rect->bottom)/2 - cy/2; // center
+                   UserDrawIconEx(hdc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
+                   UserDereferenceObject(pIcon);
+                 }
+                 return;
+            }
+            goto got_bitmap;
+        case (INT_PTR)HBMMENU_MBAR_RESTORE:
+            flags = DFCS_CAPTIONRESTORE;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
+            r.right += 1;
+            flags = DFCS_CAPTIONMIN;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
+            r.right += 1;
+            flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_CLOSE:
+            flags = DFCS_CAPTIONCLOSE;
+            break;
+        case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
+            flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
+            break;
+        case (INT_PTR)HBMMENU_CALLBACK:
+            {
+                DRAWITEMSTRUCT drawItem;
+                POINT origorg;
+                drawItem.CtlType = ODT_MENU;
+                drawItem.CtlID = 0;
+                drawItem.itemID = lpitem->wID;
+                drawItem.itemAction = odaction;
+                drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
+                drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
+                drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
+                drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
+                drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
+                drawItem.itemState |= (!(Menu->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
+                drawItem.itemState |= (Menu->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
+                drawItem.hwndItem = (HWND)UserHMGetHandle(Menu);
+                drawItem.hDC = hdc;
+                drawItem.rcItem = *rect;
+                drawItem.itemData = lpitem->dwItemData;
+                /* some applications make this assumption on the DC's origin */
+                GreSetViewportOrgEx( hdc, lpitem->xItem, lpitem->yItem, &origorg);
+                RECTL_vOffsetRect( &drawItem.rcItem, - lpitem->xItem, - lpitem->yItem);
+                co_IntSendMessage( UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM)&drawItem);
+                GreSetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+                return;
+            }
+            break;
+
+          case (INT_PTR) HBMMENU_POPUP_CLOSE:
+          case (INT_PTR) HBMMENU_POPUP_RESTORE:
+          case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+          case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+            MENU_DrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE);
+            return;
+      }
+      RECTL_vInflateRect(&r, -1, -1);
+      if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
+      DrawFrameControl(hdc, &r, DFC_CAPTION, flags);
+      return;
+    }
+
+    if (!bmp || !GreGetObject( bmp, sizeof(bm), &bm )) return;
+
+ got_bitmap:
+    hdcMem = NtGdiCreateCompatibleDC( hdc );
+    NtGdiSelectBitmap( hdcMem, bmp );
+    /* handle fontsize > bitmap_height */
+    top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
+    left=rect->left;
+    rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
+    if ((lpitem->fState & MF_HILITE) && lpitem->hbmp)
+        IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
+    NtGdiBitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop , 0, 0);
+    IntGdiDeleteDC( hdcMem, FALSE );
+}
+
+LONG
+IntGetDialogBaseUnits(VOID)
+{
+    static DWORD units;
+
+    if (!units)
+    {
+        HDC hdc;
+        SIZE size;
+
+        if ((hdc = UserGetDCEx(NULL, NULL, DCX_CACHE)))
+        {
+            size.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&size.cy );
+            if (size.cx) units = MAKELONG( size.cx, size.cy );
+            UserReleaseDC( 0, hdc, FALSE);
+        }
+    }
+    return units;
+}
+
+
+/***********************************************************************
+ *           MenuCalcItemSize
+ *
+ * Calculate the size of the menu item and store it in lpitem->rect.
+ */
+static void FASTCALL MENU_CalcItemSize( HDC hdc, PITEM lpitem, PMENU Menu, PWND pwndOwner,
+                 INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp)
+{
+    WCHAR *p;
+    UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK );
+    UINT arrow_bitmap_width;
+    RECT Rect;
+    INT itemheight = 0;
+
+    TRACE("dc=%x owner=%x (%d,%d)\n", hdc, pwndOwner, orgX, orgY);
+
+    arrow_bitmap_width = gpsi->oembmi[OBI_MNARROW].cx;
+
+    MenuCharSize.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&MenuCharSize.cy );
+
+    RECTL_vSetRect( &Rect, orgX, orgY, orgX, orgY );
+
+    if (lpitem->fType & MF_OWNERDRAW)
+    {
+        MEASUREITEMSTRUCT mis;
+        mis.CtlType    = ODT_MENU;
+        mis.CtlID      = 0;
+        mis.itemID     = lpitem->wID;
+        mis.itemData   = lpitem->dwItemData;
+        mis.itemHeight = HIWORD( IntGetDialogBaseUnits());
+        mis.itemWidth  = 0;
+        co_IntSendMessage( UserHMGetHandle(pwndOwner), WM_MEASUREITEM, 0, (LPARAM)&mis );
+        /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
+         * width of a menufont character to the width of an owner-drawn menu. 
+         */
+        Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
+        if (menuBar) {
+            /* under at least win95 you seem to be given a standard
+               height for the menu and the height value is ignored */
+            Rect.bottom += UserGetSystemMetrics(SM_CYMENUSIZE);
+        } else
+            Rect.bottom += mis.itemHeight;
+        // Or this,
+        //lpitem->cxBmp = mis.itemWidth;
+        //lpitem->cyBmp = mis.itemHeight;
+        TRACE("MF_OWNERDRAW Height %d Width %d\n",mis.itemHeight,mis.itemWidth);
+        TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
+                lpitem->wID, Rect.right-Rect.left,
+                 Rect.bottom-Rect.top, MenuCharSize.cx, MenuCharSize.cy);
+
+        lpitem->xItem = Rect.left;
+        lpitem->yItem = Rect.top;
+        lpitem->cxItem = Rect.right;
+        lpitem->cyItem = Rect.bottom;
+
+        return;
+    }
+
+    lpitem->xItem  = orgX;
+    lpitem->yItem  = orgY; 
+    lpitem->cxItem = orgX;
+    lpitem->cyItem = orgY;
+
+    if (lpitem->fType & MF_SEPARATOR)
+    {
+        lpitem->cyItem += UserGetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT;
+        if( !menuBar)
+            lpitem->cxItem += arrow_bitmap_width + MenuCharSize.cx;
+        return;
+    }
+
+    lpitem->dxTab = 0;
+
+    if (lpitem->hbmp)
+    {
+        SIZE size;
+
+        if (!menuBar) {
+            MENU_GetBitmapItemSize(lpitem, &size, pwndOwner );
+            /* Keep the size of the bitmap in callback mode to be able
+             * to draw it correctly */
+            lpitem->cxBmp = size.cx;
+            lpitem->cyBmp = size.cy;
+            Menu->cxTextAlign = max(Menu->cxTextAlign, size.cx);
+            lpitem->cxItem += size.cx + 2;
+            itemheight = size.cy + 2;
+
+            if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+                lpitem->cxItem += 2 * check_bitmap_width;
+            lpitem->cxItem += 4 + MenuCharSize.cx;
+            lpitem->dxTab = lpitem->cxItem;
+            lpitem->cxItem += arrow_bitmap_width;
+        } else /* hbmpItem & MenuBar */ {
+            MENU_GetBitmapItemSize(lpitem, &size, pwndOwner );
+            lpitem->cxItem  += size.cx;
+            if( lpitem->Xlpstr) lpitem->cxItem  += 2;
+            itemheight = size.cy;
+
+            /* Special case: Minimize button doesn't have a space behind it. */
+            if (lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
+                lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
+            lpitem->cxItem -= 1;
+        }
+    }
+    else if (!menuBar) {
+        if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+             lpitem->cxItem += check_bitmap_width;
+        lpitem->cxItem += 4 + MenuCharSize.cx;
+        lpitem->dxTab = lpitem->cxItem;
+        lpitem->cxItem += arrow_bitmap_width;
+    }
+
+    /* it must be a text item - unless it's the system menu */
+    if (!(lpitem->fType & MF_SYSMENU) && lpitem->Xlpstr) {
+        HFONT hfontOld = NULL;
+        RECT rc;// = lpitem->Rect;
+        LONG txtheight, txtwidth;
+
+        rc.left   = lpitem->xItem;
+        rc.top    = lpitem->yItem; 
+        rc.right  = lpitem->cxItem; // Do this for now......
+        rc.bottom = lpitem->cyItem;
+
+        if ( lpitem->fState & MFS_DEFAULT ) {
+            hfontOld = NtGdiSelectFont( hdc, ghMenuFontBold );
+        }
+        if (menuBar) {
+            txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc, DT_SINGLELINE|DT_CALCRECT); 
+
+            lpitem->cxItem  += rc.right - rc.left;
+            itemheight = max( max( itemheight, txtheight), UserGetSystemMetrics( SM_CYMENU) - 1);
+
+            lpitem->cxItem +=  2 * MenuCharSize.cx;
+        } else {
+            if ((p = wcschr( lpitem->Xlpstr, '\t' )) != NULL) {
+                RECT tmprc = rc;
+                LONG tmpheight;
+                int n = (int)( p - lpitem->Xlpstr);
+                /* Item contains a tab (only meaningful in popup menus) */
+                /* get text size before the tab */
+                txtheight = DrawTextW( hdc, lpitem->Xlpstr, n, &rc,
+                        DT_SINGLELINE|DT_CALCRECT);
+                txtwidth = rc.right - rc.left;
+                p += 1; /* advance past the Tab */
+                /* get text size after the tab */
+                tmpheight = DrawTextW( hdc, p, -1, &tmprc,
+                        DT_SINGLELINE|DT_CALCRECT);
+                lpitem->dxTab += txtwidth;
+                txtheight = max( txtheight, tmpheight);
+                txtwidth += MenuCharSize.cx + /* space for the tab */
+                    tmprc.right - tmprc.left; /* space for the short cut */
+            } else {
+                txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc,
+                        DT_SINGLELINE|DT_CALCRECT);
+                txtwidth = rc.right - rc.left;
+                lpitem->dxTab += txtwidth;
+            }
+            lpitem->cxItem  += 2 + txtwidth;
+            itemheight = max( itemheight,
+                                   max( txtheight + 2, MenuCharSize.cy + 4));
+        }
+        if (hfontOld)
+        {
+           NtGdiSelectFont (hdc, hfontOld);
+        }
+    } else if( menuBar) {
+        itemheight = max( itemheight, UserGetSystemMetrics(SM_CYMENU)-1);
+    }
+    lpitem->cyItem += itemheight;
+    TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->xItem, lpitem->yItem, lpitem->cxItem, lpitem->cyItem);
+}
+
+/***********************************************************************
+ *           MENU_GetMaxPopupHeight
+ */
+static UINT
+MENU_GetMaxPopupHeight(PMENU lppop)
+{
+    if (lppop->cyMax)
+    {
+       //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
+       return lppop->cyMax;
+    }
+    //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
+    return UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER);
+}
+
+/***********************************************************************
+ *           MenuPopupMenuCalcSize
+ *
+ * Calculate the size of a popup menu.
+ */
+static void FASTCALL MENU_PopupMenuCalcSize(PMENU Menu, PWND WndOwner)
+{
+    PITEM lpitem;
+    HDC hdc;
+    int start, i;
+    int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
+    BOOL textandbmp = FALSE;
+
+    Menu->cxMenu = Menu->cyMenu = 0;
+    if (Menu->cItems == 0) return;
+
+    hdc = UserGetDCEx(NULL, NULL, DCX_CACHE);
+
+    NtGdiSelectFont( hdc, ghMenuFont );
+
+    start = 0;
+    maxX = 2 + 1;
+
+    Menu->cxTextAlign = 0;
+
+    while (start < Menu->cItems)
+    {
+      lpitem = &Menu->rgItems[start];
+      orgX = maxX;
+      if( lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))
+          orgX += MENU_COL_SPACE;
+      orgY = MENU_TOP_MARGIN;
+
+      maxTab = maxTabWidth = 0;
+      /* Parse items until column break or end of menu */
+      for (i = start; i < Menu->cItems; i++, lpitem++)
+      {
+          if (i != start &&
+               (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+          MENU_CalcItemSize(hdc, lpitem, Menu, WndOwner, orgX, orgY, FALSE, textandbmp);
+          maxX = max(maxX, lpitem->cxItem);
+          orgY = lpitem->cyItem;
+          if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab )
+          {
+              maxTab = max( maxTab, lpitem->dxTab );
+              maxTabWidth = max(maxTabWidth, lpitem->cxItem - lpitem->dxTab);
+          }
+          if( lpitem->Xlpstr && lpitem->hbmp) textandbmp = TRUE;
+      }
+
+        /* Finish the column (set all items to the largest width found) */
+      maxX = max( maxX, maxTab + maxTabWidth );
+      for (lpitem = &Menu->rgItems[start]; start < i; start++, lpitem++)
+      {
+          lpitem->cxItem = maxX;
+           if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab)
+               lpitem->dxTab = maxTab;
+      }
+      Menu->cyMenu = max(Menu->cyMenu, orgY);
+    }
+
+    Menu->cxMenu  = maxX;
+    /* if none of the items have both text and bitmap then
+     * the text and bitmaps are all aligned on the left. If there is at
+     * least one item with both text and bitmap then bitmaps are
+     * on the left and texts left aligned with the right hand side
+     * of the bitmaps */
+    if( !textandbmp) Menu->cxTextAlign = 0;
+
+    /* space for 3d border */
+    Menu->cyMenu += MENU_BOTTOM_MARGIN;
+    Menu->cxMenu += 2;
+
+    /* Adjust popup height if it exceeds maximum */
+    maxHeight = MENU_GetMaxPopupHeight(Menu);
+    Menu->iMaxTop = Menu->cyMenu - MENU_TOP_MARGIN;
+    if (Menu->cyMenu >= maxHeight)
+    {
+       Menu->cyMenu = maxHeight;
+       Menu->dwArrowsOn = 1;
+    }
+    else
+    {   
+       Menu->dwArrowsOn = 0;
+    }
+    UserReleaseDC( 0, hdc, FALSE );
+}
+
+/***********************************************************************
+ *           MENU_MenuBarCalcSize
+ *
+ * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
+ * height is off by 1 pixel which causes lengthy window relocations when
+ * active document window is maximized/restored.
+ *
+ * Calculate the size of the menu bar.
+ */
+static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, PMENU lppop, PWND pwndOwner )
+{
+    ITEM *lpitem;
+    UINT start, i, helpPos;
+    int orgX, orgY, maxY;
+
+    if ((lprect == NULL) || (lppop == NULL)) return;
+    if (lppop->cItems == 0) return;
+    //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
+    lppop->cxMenu  = lprect->right - lprect->left;
+    lppop->cyMenu = 0;
+    maxY = lprect->top+1;
+    start = 0;
+    helpPos = ~0U;
+    lppop->cxTextAlign = 0;
+    while (start < lppop->cItems)
+    {
+       lpitem = &lppop->rgItems[start];
+       orgX = lprect->left;
+       orgY = maxY;
+
+         /* Parse items until line break or end of menu */
+       for (i = start; i < lppop->cItems; i++, lpitem++)
+       {
+           if ((helpPos == ~0U) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
+           if ((i != start) &&
+               (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+           TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY );
+           //debug_print_menuitem ("  item: ", lpitem, "");
+           //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
+            MENU_CalcItemSize(hdc, lpitem, lppop, pwndOwner, orgX, orgY, TRUE, FALSE);
+
+           if (lpitem->cxItem > lprect->right)
+           {
+               if (i != start) break;
+               else lpitem->cxItem = lprect->right;
+           }
+           maxY = max( maxY, lpitem->cyItem );
+           orgX = lpitem->cxItem;
+       }
+
+         /* Finish the line (set all items to the largest height found) */
+
+/* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
+   HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
+#if 0
+       while (start < i) lppop->rgItems[start++].cyItem = maxY;
+#endif
+       start = i; /* This works! */
+    }
+
+    lprect->bottom = maxY;
+    lppop->cyMenu = lprect->bottom - lprect->top;
+
+    /* Flush right all items between the MF_RIGHTJUSTIFY and */
+    /* the last item (if several lines, only move the last line) */
+    if (helpPos == ~0U) return;
+    lpitem = &lppop->rgItems[lppop->cItems-1];
+    orgY = lpitem->yItem;
+    orgX = lprect->right;
+    for (i = lppop->cItems - 1; i >= helpPos; i--, lpitem--) {
+        if (lpitem->yItem != orgY) break;      /* Other line */
+        if (lpitem->cxItem >= orgX) break;     /* Too far right already */
+        lpitem->xItem += orgX - lpitem->cxItem;
+        lpitem->cxItem = orgX;
+        orgX = lpitem->xItem;
+    }
+}
+
+/***********************************************************************
+ *           MENU_DrawScrollArrows
+ *
+ * Draw scroll arrows.
+ */
+static void MENU_DrawScrollArrows(PMENU lppop, HDC hdc)
+{
+    UINT arrow_bitmap_width, arrow_bitmap_height;
+    RECT rect, dfcrc;
+    UINT Flags = 0;
+
+    arrow_bitmap_width  = gpsi->oembmi[OBI_DNARROW].cx;
+    arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
+
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = lppop->cxMenu;
+    rect.bottom = arrow_bitmap_height;
+    FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
+    dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
+    dfcrc.top = 0;
+    dfcrc.right = arrow_bitmap_width;
+    dfcrc.bottom = arrow_bitmap_height;
+    DrawFrameControl(hdc, &dfcrc, DFC_MENU, (lppop->iTop ? 0 : DFCS_INACTIVE)|DFCS_MENUARROWUP);
+
+    rect.top = lppop->cyMenu - arrow_bitmap_height;
+    rect.bottom = lppop->cyMenu;
+    FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
+    if (!(lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height)))
+       Flags = DFCS_INACTIVE;
+    dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
+    dfcrc.top = lppop->cyMenu - arrow_bitmap_height;
+    dfcrc.right = arrow_bitmap_width;
+    dfcrc.bottom = lppop->cyMenu;
+    DrawFrameControl(hdc, &dfcrc, DFC_MENU, Flags|DFCS_MENUARROWDOWN);
+}
+
+/***********************************************************************
+ *           MenuDrawMenuItem
+ *
+ * Draw a single menu item.
+ */
+static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC hdc,
+                 PITEM lpitem, UINT Height, BOOL menuBar, UINT odaction)
+{
+    RECT rect;
+    PWCHAR Text;
+    BOOL flat_menu = FALSE;
+    int bkgnd;
+    UINT arrow_bitmap_width = 0;
+
+    if (!menuBar) {
+        arrow_bitmap_width  = gpsi->oembmi[OBI_MNARROW].cx; 
+    }
+
+    if (lpitem->fType & MF_SYSMENU)
+    {
+        if ( (Wnd->style & WS_MINIMIZE))
+        {
+          UserGetInsideRectNC(Wnd, &rect);
+          UserDrawSysMenuButton(Wnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
+       }
+        return;
+    }
+
+    UserSystemParametersInfo (SPI_GETFLATMENU, 0, &flat_menu, 0);
+    bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
+  
+    /* Setup colors */
+
+    if (lpitem->fState & MF_HILITE)
+    {
+        if(menuBar && !flat_menu) {
+            IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_MENUTEXT));
+            IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_MENU));
+        } else {
+            if (lpitem->fState & MF_GRAYED)
+                IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_GRAYTEXT));
+            else
+                IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_HIGHLIGHTTEXT));
+            IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
+        }
+    }
+    else
+    {
+        if (lpitem->fState & MF_GRAYED)
+            IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_GRAYTEXT ) );
+        else
+            IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_MENUTEXT ) );
+        IntGdiSetBkColor( hdc, IntGetSysColor( bkgnd ) );
+    }
+
+    //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
+    //rect = lpitem->Rect;
+    rect.left   = lpitem->xItem;
+    rect.top    = lpitem->yItem; 
+    rect.right  = lpitem->cxItem; // Do this for now......
+    rect.bottom = lpitem->cyItem;
+
+    MENU_AdjustMenuItemRect(Menu, &rect);
+
+    if (lpitem->fType & MF_OWNERDRAW)
+    {
+        /*
+        ** Experimentation under Windows reveals that an owner-drawn
+        ** menu is given the rectangle which includes the space it requested
+        ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
+        ** and a popup-menu arrow.  This is the value of lpitem->rect.
+        ** Windows will leave all drawing to the application except for
+        ** the popup-menu arrow.  Windows always draws that itself, after
+        ** the menu owner has finished drawing.
+        */
+        DRAWITEMSTRUCT dis;
+
+        dis.CtlType   = ODT_MENU;
+        dis.CtlID     = 0;
+        dis.itemID    = lpitem->wID;
+        dis.itemData  = (DWORD)lpitem->dwItemData;
+        dis.itemState = 0;
+        if (lpitem->fState & MF_CHECKED)  dis.itemState |= ODS_CHECKED;
+        if (lpitem->fState & MF_DEFAULT)  dis.itemState |= ODS_DEFAULT;
+        if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
+        if (lpitem->fState & MF_GRAYED)   dis.itemState |= ODS_GRAYED | ODS_DISABLED;
+        if (lpitem->fState & MF_HILITE)   dis.itemState |= ODS_SELECTED;
+        if (!(Menu->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
+        if (Menu->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
+        dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
+        dis.hwndItem   = (HWND) UserHMGetHandle(Menu);
+        dis.hDC        = hdc;
+        dis.rcItem     = rect;
+        TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
+               "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd,
+               dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
+               dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
+               dis.rcItem.bottom);
+        TRACE("Ownerdraw: Width %d Height %d\n", dis.rcItem.right-dis.rcItem.left, dis.rcItem.bottom-dis.rcItem.top);
+        co_IntSendMessage(UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM) &dis);
+        /* Draw the popup-menu arrow */
+        if (lpitem->spSubMenu)
+        {
+            RECT rectTemp;
+            RtlCopyMemory(&rectTemp, &rect, sizeof(RECT));
+            rectTemp.left = rectTemp.right - UserGetSystemMetrics(SM_CXMENUCHECK);
+            DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+        }
+        return;
+    }
+
+    if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
+
+    if (lpitem->fState & MF_HILITE)
+    {
+        if (flat_menu)
+        {
+            RECTL_vInflateRect (&rect, -1, -1);
+            FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENUHILIGHT));
+            RECTL_vInflateRect (&rect, 1, 1);
+            FrameRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT));
+        }
+        else
+        {
+            if(menuBar)
+                DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
+            else
+                FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT));
+        }
+    }
+    else
+        FillRect( hdc, &rect, IntGetSysColorBrush(bkgnd) );
+
+    IntGdiSetBkMode( hdc, TRANSPARENT );
+
+    /* vertical separator */
+    if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
+    {
+        HPEN oldPen;
+        RECT rc = rect;
+
+        rc.left -= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
+        rc.top = 3;
+        rc.bottom = Height - 3;
+        if (flat_menu)
+        {
+            oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
+            IntSetDCPenColor(hdc, IntGetSysColor(COLOR_BTNSHADOW));
+            GreMoveTo( hdc, rc.left, rc.top, NULL );
+            NtGdiLineTo( hdc, rc.left, rc.bottom );
+            NtGdiSelectPen( hdc, oldPen );
+        }
+        else
+            DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
+    }
+
+    /* horizontal separator */
+    if (lpitem->fType & MF_SEPARATOR)
+    {
+        HPEN oldPen;
+        RECT rc = rect;
+
+        rc.left++;
+        rc.right--;
+        rc.top += SEPARATOR_HEIGHT / 2;
+        if (flat_menu)
+        {
+            oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
+            IntSetDCPenColor( hdc, IntGetSysColor(COLOR_BTNSHADOW));
+            GreMoveTo( hdc, rc.left, rc.top, NULL );
+            NtGdiLineTo( hdc, rc.right, rc.top );
+            NtGdiSelectPen( hdc, oldPen );
+        }
+        else
+            DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
+        return;
+    }
+
+#if 0
+    /* helper lines for debugging */
+    /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
+    FrameRect(hdc, &rect, NtGdiGetStockObject(BLACK_BRUSH));
+    NtGdiSelectPen(hdc, NtGdiGetStockObject(DC_PEN));
+    IntSetDCPenColor(hdc, IntGetSysColor(COLOR_WINDOWFRAME));
+    GreMoveTo(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
+    NtGdiLineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
+#endif
+
+    if (!menuBar)
+    {
+        HBITMAP bm;
+        INT y = rect.top + rect.bottom;
+        RECT rc = rect;
+        BOOL checked = FALSE;
+        UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK );
+        UINT check_bitmap_height = UserGetSystemMetrics( SM_CYMENUCHECK );
+        /* Draw the check mark
+         *
+         * FIXME:
+         * Custom checkmark bitmaps are monochrome but not always 1bpp.
+         */
+        if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) {
+            bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked : 
+                lpitem->hbmpUnchecked;
+            if (bm)  /* we have a custom bitmap */
+            {
+                HDC hdcMem = NtGdiCreateCompatibleDC( hdc );
+
+                NtGdiSelectBitmap( hdcMem, bm );
+                NtGdiBitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
+                        check_bitmap_width, check_bitmap_height,
+                        hdcMem, 0, 0, SRCCOPY, 0,0);
+                IntGdiDeleteDC( hdcMem, FALSE );
+                checked = TRUE;
+            }
+            else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
+            {
+                RECT r;
+                r = rect;
+                r.right = r.left + UserGetSystemMetrics(SM_CXMENUCHECK);
+                DrawFrameControl( hdc, &r, DFC_MENU,
+                                 (lpitem->fType & MFT_RADIOCHECK) ?
+                                 DFCS_MENUBULLET : DFCS_MENUCHECK);
+                checked = TRUE;
+            }
+        }
+        if ( lpitem->hbmp )//&& !( checked && (Menu->dwStyle & MNS_CHECKORBMP)))
+        {
+            RECT bmpRect;
+            //CopyRect(&bmpRect, &rect);
+            bmpRect = rect;
+            if (!((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP) && !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+                bmpRect.left += check_bitmap_width + 2;
+            if (!(checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
+            {
+                //POINT origorg;
+                bmpRect.right = bmpRect.left + lpitem->cxBmp;
+                /* some applications make this assumption on the DC's origin */
+                //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
+                MENU_DrawBitmapItem(hdc, lpitem, &bmpRect, Menu, WndOwner, odaction, menuBar);
+                //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+            }
+        }
+        /* Draw the popup-menu arrow */
+        if (lpitem->spSubMenu)
+        {
+            RECT rectTemp;
+            RtlCopyMemory(&rectTemp, &rect, sizeof(RECT));
+            rectTemp.left = rectTemp.right - UserGetSystemMetrics(SM_CXMENUCHECK);
+            DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+        }
+        rect.left += 4;
+        if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
+            rect.left += check_bitmap_width;
+        rect.right -= arrow_bitmap_width;//check_bitmap_width;
+    }
+    else if( lpitem->hbmp)
+    { /* Draw the bitmap */
+        //POINT origorg;
+
+        //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
+        MENU_DrawBitmapItem(hdc, lpitem, &rect, Menu, WndOwner, odaction, menuBar);
+        //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+    }
+
+    /* process text if present */
+    if (lpitem->Xlpstr)
+    {
+        int i = 0;
+        HFONT hfontOld = 0;
+
+        UINT uFormat = menuBar ?
+                       DT_CENTER | DT_VCENTER | DT_SINGLELINE :
+                       DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+
+        if (((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP))
+             rect.left += max(0, (int)(Menu->cxTextAlign - UserGetSystemMetrics(SM_CXMENUCHECK)));
+        else
+             rect.left += Menu->cxTextAlign;
+
+        if ( lpitem->fState & MFS_DEFAULT )
+        {
+            hfontOld = NtGdiSelectFont(hdc, ghMenuFontBold);            
+        }
+
+        if (menuBar) {
+            if( lpitem->hbmp)
+              rect.left += lpitem->cxBmp;
+            if( !(lpitem->hbmp == HBMMENU_CALLBACK)) 
+              rect.left += MenuCharSize.cx;
+            rect.right -= MenuCharSize.cx;
+            //rect.left += MENU_BAR_ITEMS_SPACE / 2;
+            //rect.right -= MENU_BAR_ITEMS_SPACE / 2;
+        }
+
+        Text = lpitem->Xlpstr;
+        if(Text)
+        {
+            for (i = 0; L'\0' != Text[i]; i++)
+                if (Text[i] == L'\t' || Text[i] == L'\b')
+                    break;
+        }
+
+        if(lpitem->fState & MF_GRAYED)
+        {
+            if (!(lpitem->fState & MF_HILITE) )
+            {
+                ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+                IntGdiSetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+                DrawTextW( hdc, Text, i, &rect, uFormat );
+                --rect.left; --rect.top; --rect.right; --rect.bottom;
+            }
+            IntGdiSetTextColor(hdc, RGB(0x80, 0x80, 0x80));
+        }
+        DrawTextW( hdc, Text, i, &rect, uFormat);
+
+        /* paint the shortcut text */
+        if (!menuBar && L'\0' != Text[i])  /* There's a tab or flush-right char */
+        {
+            if (L'\t' == Text[i])
+            {
+                rect.left = lpitem->dxTab;
+                uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+            }
+            else
+            {
+                rect.right = lpitem->dxTab;
+                uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
+            }
+
+            if (lpitem->fState & MF_GRAYED)
+            {
+                if (!(lpitem->fState & MF_HILITE) )
+                {
+                    ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+                    IntGdiSetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+                    DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
+                    --rect.left; --rect.top; --rect.right; --rect.bottom;
+                }
+                IntGdiSetTextColor(hdc, RGB(0x80, 0x80, 0x80));
+            }
+            DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
+        }
+
+        if (hfontOld)
+        {
+           NtGdiSelectFont (hdc, hfontOld);
+        }
+    }
+}
+
+/***********************************************************************
+ *           MenuDrawPopupMenu
+ *
+ * Paint a popup menu.
+ */
+static void FASTCALL MENU_DrawPopupMenu(PWND wnd, HDC hdc, PMENU menu )
+{
+    HBRUSH hPrevBrush = 0, brush = IntGetSysColorBrush(COLOR_MENU);
+    RECT rect;
+
+    TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd, hdc, menu);
+
+    IntGetClientRect( wnd, &rect );
+
+    if (menu && menu->hbrBack) brush = menu->hbrBack;
+    if((hPrevBrush = NtGdiSelectBrush( hdc, brush ))
+        && (NtGdiSelectFont( hdc, ghMenuFont)))
+    {
+        HPEN hPrevPen;
+
+        NtGdiRectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
+
+        hPrevPen = NtGdiSelectPen( hdc, NtGdiGetStockObject( NULL_PEN ) );
+        if ( hPrevPen )
+        {
+            BOOL flat_menu = FALSE;
+
+            UserSystemParametersInfo (SPI_GETFLATMENU, 0, &flat_menu, 0);
+            if (flat_menu)
+               FrameRect(hdc, &rect, IntGetSysColorBrush(COLOR_BTNSHADOW));
+            else
+               DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
+
+            TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu), (menu->fFlags & MNS_STYLE_MASK));
+            /* draw menu items */
+            if (menu && menu->cItems)
+            {
+                ITEM *item;
+                UINT u;
+
+                item = menu->rgItems;
+                for (u = 0; u < menu->cItems; u++, item++)
+                {
+                    MENU_DrawMenuItem(wnd, menu, menu->spwndNotify, hdc, item,
+                                         menu->cyMenu, FALSE, ODA_DRAWENTIRE);
+                }
+                /* draw scroll arrows */
+                if (menu->dwArrowsOn)
+                {
+                   MENU_DrawScrollArrows(menu, hdc);
+                }
+            }
+        }
+        else
+        {
+            NtGdiSelectBrush( hdc, hPrevBrush );
+        }
+    }
+}
+
+/**********************************************************************
+ *         MENU_IsMenuActive
+ */
+PWND MENU_IsMenuActive(VOID)
+{
+   return ValidateHwndNoErr(top_popup);
+}
+
+/**********************************************************************
+ *         MENU_EndMenu
+ *
+ * Calls EndMenu() if the hwnd parameter belongs to the menu owner
+ *
+ * Does the (menu stuff) of the default window handling of WM_CANCELMODE
+ */
+void MENU_EndMenu( PWND pwnd )
+{
+    PMENU menu = NULL;
+    menu = UserGetMenuObject(top_popup_hmenu);
+    if ( menu && ( UserHMGetHandle(pwnd) == menu->hWnd || pwnd == menu->spwndNotify ) )
+    {
+       if (fInsideMenuLoop && top_popup)
+       {
+          fInsideMenuLoop = FALSE;
+
+          if (fInEndMenu)
+          {
+             ERR("Already in End loop\n");
+             return;
+          }
+
+          fInEndMenu = TRUE;
+          UserPostMessage( top_popup, WM_CANCELMODE, 0, 0);
+       }
+    }
+}
+
+DWORD WINAPI
+IntDrawMenuBarTemp(PWND pWnd, HDC hDC, LPRECT Rect, PMENU pMenu, HFONT Font)
+{
+  UINT i;
+  HFONT FontOld = NULL;
+  BOOL flat_menu = FALSE;
+
+  UserSystemParametersInfo(SPI_GETFLATMENU, 0, &flat_menu, 0);
+
+  if (!pMenu)
+  {
+      pMenu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
+  }
+
+  if (!Font)
+  {
+      Font = ghMenuFont;
+  }
+
+  if (Rect == NULL || !pMenu)
+  {
+      return UserGetSystemMetrics(SM_CYMENU);
+  }
+
+  TRACE("(%x, %x, %p, %x, %x)\n", pWnd, hDC, Rect, pMenu, Font);
+
+  FontOld = NtGdiSelectFont(hDC, Font);
+
+  if (pMenu->cyMenu == 0)
+  {
+      MENU_MenuBarCalcSize(hDC, Rect, pMenu, pWnd);
+  }
+
+  Rect->bottom = Rect->top + pMenu->cyMenu;
+
+  FillRect(hDC, Rect, IntGetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
+
+  NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
+  IntSetDCPenColor(hDC, IntGetSysColor(COLOR_3DFACE));
+  GreMoveTo(hDC, Rect->left, Rect->bottom - 1, NULL);
+  NtGdiLineTo(hDC, Rect->right, Rect->bottom - 1);
+
+  if (pMenu->cItems == 0)
+  {
+      NtGdiSelectFont(hDC, FontOld);
+      return UserGetSystemMetrics(SM_CYMENU);
+  }
+
+  for (i = 0; i < pMenu->cItems; i++)
+  {
+      MENU_DrawMenuItem(pWnd, pMenu, pWnd, hDC, &pMenu->rgItems[i], pMenu->cyMenu, TRUE, ODA_DRAWENTIRE);
+  }
+
+  NtGdiSelectFont(hDC, FontOld);
+
+  return pMenu->cyMenu;
+}
+
+UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, PWND pWnd, BOOL suppress_draw )
+{
+    HFONT hfontOld = 0;
+    PMENU lppop = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
+
+    if (lppop == NULL || lprect == NULL)
+    {
+        return UserGetSystemMetrics(SM_CYMENU);
+    }
+
+    if (suppress_draw)
+    {
+       hfontOld = NtGdiSelectFont(hDC, ghMenuFont);
+
+       MENU_MenuBarCalcSize(hDC, lprect, lppop, pWnd);
+
+       lprect->bottom = lprect->top + lppop->cyMenu;
+
+       if (hfontOld) NtGdiSelectFont( hDC, hfontOld);
+
+       return lppop->cyMenu;
+    }   
+    else
+    {
+       return IntDrawMenuBarTemp(pWnd, hDC, lprect, lppop, NULL);
+    }
+}
+
+/***********************************************************************
+ *           MENU_InitPopup
+ *   
+ * Popup menu initialization before WM_ENTERMENULOOP.
+ */
+static BOOL MENU_InitPopup( PWND pWndOwner, PMENU menu, UINT flags )
+{
+    PWND pWndCreated;
+    PPOPUPMENU pPopupMenu;
+    CREATESTRUCTW Cs;
+    LARGE_STRING WindowName;
+    UNICODE_STRING ClassName;
+    DWORD ex_style = WS_EX_TOOLWINDOW;
+
+    TRACE("owner=%p hmenu=%p\n", pWndOwner, menu);
+
+    menu->spwndNotify = pWndOwner;
+
+    if (flags & TPM_LAYOUTRTL || pWndOwner->ExStyle & WS_EX_LAYOUTRTL)
+       ex_style = WS_EX_LAYOUTRTL;
+
+    ClassName.Buffer = WC_MENU;
+    ClassName.Length = 0;
+
+    RtlZeroMemory(&WindowName, sizeof(WindowName));
+    RtlZeroMemory(&Cs, sizeof(Cs));
+    Cs.style = WS_POPUP;
+    Cs.dwExStyle = ex_style;
+    Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
+    Cs.lpszName = (LPCWSTR) &WindowName;
+    Cs.lpszClass = (LPCWSTR) &ClassName;
+    Cs.lpCreateParams = UserHMGetHandle(menu);
+    Cs.hwndParent = UserHMGetHandle(pWndOwner);
+
+    /* NOTE: In Windows, top menu popup is not owned. */
+    pWndCreated = co_UserCreateWindowEx( &Cs, &ClassName, &WindowName, NULL);
+
+    if( !pWndCreated ) return FALSE;
+
+    //
+    //  Setup pop up menu structure.
+    //
+    menu->hWnd = UserHMGetHandle(pWndCreated);
+
+    pPopupMenu = ((PMENUWND)pWndCreated)->ppopupmenu;
+
+    pPopupMenu->spwndActivePopup = pWndCreated; // top_popup = MenuInfo.Wnd or menu->hWnd
+    pPopupMenu->spwndNotify = pWndOwner;        // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
+    //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
+
+    pPopupMenu->fIsTrackPopup = !!(flags & TPM_POPUPMENU);
+    pPopupMenu->fIsSysMenu    = !!(flags & TPM_SYSTEM_MENU);
+    pPopupMenu->fNoNotify     = !!(flags & TPM_NONOTIFY);
+    pPopupMenu->fRightButton  = !!(flags & TPM_RIGHTBUTTON);
+    pPopupMenu->fSynchronous  = !!(flags & TPM_RETURNCMD);
+
+    if (pPopupMenu->fRightButton)
+       pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_RBUTTON) & 0x8000);
+    else
+       pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_LBUTTON) & 0x8000);
+
+    if (gpsi->aiSysMet[SM_MENUDROPALIGNMENT] ||
+        menu->fFlags & MNF_RTOL)
+    {
+       pPopupMenu->fDroppedLeft = TRUE;
+    }
+    return TRUE;
+}
+
+/***********************************************************************
+ *           MenuShowPopup
+ *
+ * Display a popup menu.
+ */
+static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT flags,
+                              INT x, INT y, INT xanchor, INT yanchor )
+{
+    UINT width, height;
+    POINT pt;
+    PMONITOR monitor;
+    PWND pWnd;
+    USER_REFERENCE_ENTRY Ref;
+
+    TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
+          pwndOwner, menu, id, x, y, xanchor, yanchor);
+
+    if (menu->iItem != NO_SELECTED_ITEM)
+    {
+        menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
+        menu->iItem = NO_SELECTED_ITEM;
+    }
+
+    menu->dwArrowsOn = 0;
+    MENU_PopupMenuCalcSize(menu, pwndOwner);
+
+    /* adjust popup menu pos so that it fits within the desktop */
+
+    width = menu->cxMenu + UserGetSystemMetrics(SM_CXBORDER);
+    height = menu->cyMenu + UserGetSystemMetrics(SM_CYBORDER);
+
+    /* FIXME: should use item rect */
+    pt.x = x;
+    pt.y = y;
+    monitor = UserMonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
+
+    if (flags & TPM_LAYOUTRTL) 
+        flags ^= TPM_RIGHTALIGN;
+
+    if( flags & TPM_RIGHTALIGN ) x -= width;
+    if( flags & TPM_CENTERALIGN ) x -= width / 2;
+
+    if( flags & TPM_BOTTOMALIGN ) y -= height;
+    if( flags & TPM_VCENTERALIGN ) y -= height / 2;
+
+    if( x + width > monitor->rcMonitor.right)
+    {
+        if( xanchor && x >= width - xanchor )
+            x -= width - xanchor;
+
+        if( x + width > monitor->rcMonitor.right)
+            x = monitor->rcMonitor.right - width;
+    }
+    if( x < monitor->rcMonitor.left ) x = monitor->rcMonitor.left;
+
+    if( y + height > monitor->rcMonitor.bottom)
+    {
+        if( yanchor && y >= height + yanchor )
+            y -= height + yanchor;
+
+        if( y + height > monitor->rcMonitor.bottom)
+            y = monitor->rcMonitor.bottom - height;
+    }
+    if( y < monitor->rcMonitor.top ) y = monitor->rcMonitor.top;
+
+    pWnd = ValidateHwndNoErr( menu->hWnd );
+
+    if (!pWnd)
+    {
+       ERR("menu->hWnd bad hwnd %p\n",menu->hWnd);
+       return FALSE;
+    }
+
+    if (!top_popup) {
+        top_popup = menu->hWnd;
+        top_popup_hmenu = UserHMGetHandle(menu);
+    }
+
+    /* Display the window */
+    UserRefObjectCo(pWnd, &Ref);
+    co_WinPosSetWindowPos( pWnd, HWND_TOPMOST, x, y, width, height, SWP_SHOWWINDOW | SWP_NOACTIVATE);
+
+    co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
+
+    IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
+    UserDerefObjectCo(pWnd);
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *           MENU_EnsureMenuItemVisible
+ */
+void MENU_EnsureMenuItemVisible(PMENU lppop, UINT wIndex, HDC hdc)
+{
+    USER_REFERENCE_ENTRY Ref;
+    if (lppop->dwArrowsOn)
+    {
+        ITEM *item = &lppop->rgItems[wIndex];
+        UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
+        UINT nOldPos = lppop->iTop;
+        RECT rc;
+        UINT arrow_bitmap_height;
+        PWND pWnd = ValidateHwndNoErr(lppop->hWnd);
+
+        IntGetClientRect(pWnd, &rc);
+
+        arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
+
+        rc.top += arrow_bitmap_height;
+        rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
+
+        nMaxHeight -= UserGetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
+        UserRefObjectCo(pWnd, &Ref);
+        if (item->cyItem > lppop->iTop + nMaxHeight)
+        {
+            lppop->iTop = item->cyItem - nMaxHeight;
+            IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+            MENU_DrawScrollArrows(lppop, hdc);
+            //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
+        }
+        else if (item->yItem - MENU_TOP_MARGIN < lppop->iTop)
+        {
+            lppop->iTop = item->yItem - MENU_TOP_MARGIN;
+            IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+            MENU_DrawScrollArrows(lppop, hdc);
+            //ERR("Scroll Up   iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
+        }
+        UserDerefObjectCo(pWnd);
+    }
+}
+
+/***********************************************************************
+ *           MenuSelectItem
+ */
+static void FASTCALL MENU_SelectItem(PWND pwndOwner, PMENU menu, UINT wIndex,
+                                    BOOL sendMenuSelect, PMENU topmenu)
+{
+    HDC hdc;
+    PWND pWnd = ValidateHwndNoErr(menu->hWnd);
+
+    TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner, menu, wIndex, sendMenuSelect);
+
+    if (!menu || !menu->cItems || !pWnd) return;
+
+    if (menu->iItem == wIndex) return;
+
+    if (menu->fFlags & MNF_POPUP)
+       hdc = UserGetDCEx(pWnd, 0, DCX_USESTYLE);
+    else
+       hdc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
+
+    if (!top_popup) {
+        top_popup = menu->hWnd;                  //pPopupMenu->spwndActivePopup or
+                                                 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
+        top_popup_hmenu = UserHMGetHandle(menu); //pPopupMenu->spmenu
+    }
+
+    NtGdiSelectFont( hdc, ghMenuFont );
+
+     /* Clear previous highlighted item */
+    if (menu->iItem != NO_SELECTED_ITEM)
+    {
+        menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
+        MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc, &menu->rgItems[menu->iItem],
+                       menu->cyMenu, !(menu->fFlags & MNF_POPUP),
+                       ODA_SELECT);
+    }
+
+    /* Highlight new item (if any) */
+    menu->iItem = wIndex;
+    if (menu->iItem != NO_SELECTED_ITEM)
+    {
+        if (!(menu->rgItems[wIndex].fType & MF_SEPARATOR))
+        {
+             menu->rgItems[wIndex].fState |= MF_HILITE;
+             MENU_EnsureMenuItemVisible(menu, wIndex, hdc);
+             MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc,
+                               &menu->rgItems[wIndex], menu->cyMenu, !(menu->fFlags & MNF_POPUP), ODA_SELECT);
+        }
+        if (sendMenuSelect)
+        {
+           ITEM *ip = &menu->rgItems[menu->iItem];
+           WPARAM wParam = MAKEWPARAM( ip->spSubMenu ? wIndex : ip->wID, 
+                                       ip->fType | ip->fState |
+                                      (ip->spSubMenu ? MF_POPUP : 0) |
+                                      (menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
+
+           co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(menu));
+        }
+    }
+    else if (sendMenuSelect) 
+    {
+        if (topmenu) 
+        {
+            int pos;
+            pos = MENU_FindSubMenu(&topmenu, menu);
+            if (pos != NO_SELECTED_ITEM)
+            {
+               ITEM *ip = &topmenu->rgItems[pos];
+               WPARAM wParam = MAKEWPARAM( Pos, ip->fType | ip->fState |
+                                           (ip->spSubMenu ? MF_POPUP : 0) |
+                                           (topmenu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
+
+               co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(topmenu));
+            }
+        }
+    }
+    UserReleaseDC(pWnd, hdc, FALSE);
+}
+
+/***********************************************************************
+ *           MenuMoveSelection
+ *
+ * Moves currently selected item according to the Offset parameter.
+ * If there is no selection then it should select the last item if
+ * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
+ */
+static void FASTCALL MENU_MoveSelection(PWND pwndOwner, PMENU menu, INT offset)
+{
+    INT i;
+
+    TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner, menu, offset);
+
+    if ((!menu) || (!menu->rgItems)) return;
+
+    if ( menu->iItem != NO_SELECTED_ITEM )
+    {
+       if ( menu->cItems == 1 )
+          return;
+       else
+       for (i = menu->iItem + offset ; i >= 0 && i < menu->cItems
+                                           ; i += offset)
+           if (!(menu->rgItems[i].fType & MF_SEPARATOR))
+           {
+               MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 );
+               return;
+           }
+    }
+
+    for ( i = (offset > 0) ? 0 : menu->cItems - 1;
+                 i >= 0 && i < menu->cItems ; i += offset)
+       if (!(menu->rgItems[i].fType & MF_SEPARATOR))
+       {
+           MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 );
+           return;
+       }
+}
+
+/***********************************************************************
+ *           MenuHideSubPopups
+ *
+ * Hide the sub-popup menus of this menu.
+ */
+static void FASTCALL MENU_HideSubPopups(PWND pWndOwner, PMENU Menu,
+                               BOOL SendMenuSelect, UINT wFlags)
+{
+  TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner, Menu, SendMenuSelect);
+
+  if ( Menu && top_popup )
+  {
+      PITEM Item;
+
+      if (Menu->iItem != NO_SELECTED_ITEM)
+      {
+         Item = &Menu->rgItems[Menu->iItem];
+         if (!(Item->spSubMenu) ||
+             !(Item->fState & MF_MOUSESELECT)) return;
+         Item->fState &= ~MF_MOUSESELECT;
+      }
+      else
+         return;
+
+      if (Item->spSubMenu)
+      {
+          PWND pWnd;
+          if (!VerifyMenu(Item->spSubMenu)) return;
+          pWnd = ValidateHwndNoErr(Item->spSubMenu->hWnd);
+          MENU_HideSubPopups(pWndOwner, Item->spSubMenu, FALSE, wFlags);
+          MENU_SelectItem(pWndOwner, Item->spSubMenu, NO_SELECTED_ITEM, SendMenuSelect, NULL);
+          TRACE("M_HSP top p hm %p  pWndOwner IDMenu %p\n",top_popup_hmenu,pWndOwner->IDMenu);
+          co_UserDestroyWindow(pWnd);
+
+          /* Native returns handle to destroyed window */
+          if (!(wFlags & TPM_NONOTIFY))
+          {
+             co_IntSendMessage( UserHMGetHandle(pWndOwner), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(Item->spSubMenu),
+                                 MAKELPARAM(0, IS_SYSTEM_MENU(Item->spSubMenu)) );
+          }
+          ////
+          // Call WM_UNINITMENUPOPUP FIRST before destroy!!
+          // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
+          //
+          Item->spSubMenu->hWnd = NULL;
+          ////
+      }
+  }
+}
+
+/***********************************************************************
+ *           MenuShowSubPopup
+ *
+ * Display the sub-menu of the selected item of this menu.
+ * Return the handle of the submenu, or menu if no submenu to display.
+ */
+static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT Flags)
+{
+  RECT Rect;
+  ITEM *Item;
+  HDC Dc;
+  PWND pWnd;
+
+  TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, Menu, SelectFirst);
+
+  if (Menu->iItem == NO_SELECTED_ITEM) return Menu;
+  
+  Item = &Menu->rgItems[Menu->iItem];
+  if (!(Item->spSubMenu) || (Item->fState & (MF_GRAYED | MF_DISABLED)))
+      return Menu;
+
+  /* message must be sent before using item,
+     because nearly everything may be changed by the application ! */
+
+  /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+  if (!(Flags & TPM_NONOTIFY))
+  {
+      co_IntSendMessage(UserHMGetHandle(WndOwner), WM_INITMENUPOPUP,
+                        (WPARAM) UserHMGetHandle(Item->spSubMenu),
+                         MAKELPARAM(Menu->iItem, IS_SYSTEM_MENU(Menu)));
+  }
+
+  Item = &Menu->rgItems[Menu->iItem];
+  //Rect = ItemInfo.Rect;
+  Rect.left   = Item->xItem;
+  Rect.top    = Item->yItem;
+  Rect.right  = Item->cxItem; // Do this for now......
+  Rect.bottom = Item->cyItem;
+
+  pWnd = ValidateHwndNoErr(Menu->hWnd);
+
+  /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
+  if (!(Item->fState & MF_HILITE))
+  {
+      if (Menu->fFlags & MNF_POPUP) Dc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE);
+      else Dc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
+
+      NtGdiSelectFont(Dc, ghMenuFont);
+
+      Item->fState |= MF_HILITE;
+      MENU_DrawMenuItem(pWnd, Menu, WndOwner, Dc, Item, Menu->cyMenu,
+                       !(Menu->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
+
+      UserReleaseDC(pWnd, Dc, FALSE);
+  }
+
+  if (!Item->yItem && !Item->xItem && !Item->cyItem && !Item->cxItem)
+  {
+      Item->xItem  = Rect.left; 
+      Item->yItem  = Rect.top;  
+      Item->cxItem = Rect.right; // Do this for now...... 
+      Item->cyItem = Rect.bottom;
+  }
+  Item->fState |= MF_MOUSESELECT;
+
+  if (IS_SYSTEM_MENU(Menu))
+  {
+      MENU_InitSysMenuPopup(Item->spSubMenu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
+
+      NC_GetSysPopupPos(pWnd, &Rect);
+      if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right;
+      Rect.top = Rect.bottom;
+      Rect.right = UserGetSystemMetrics(SM_CXSIZE);
+      Rect.bottom = UserGetSystemMetrics(SM_CYSIZE);
+  }
+  else
+  {
+      IntGetWindowRect(pWnd, &Rect);
+      if (Menu->fFlags & MNF_POPUP)
+      {
+          RECT rc;
+          rc.left   = Item->xItem;
+          rc.top    = Item->yItem;
+          rc.right  = Item->cxItem; // Do this for now......
+          rc.bottom = Item->cyItem;
+
+          MENU_AdjustMenuItemRect(Menu, &rc);
+
+          /* The first item in the popup menu has to be at the
+             same y position as the focused menu item */
+          if(Flags & TPM_LAYOUTRTL)
+             Rect.left += UserGetSystemMetrics(SM_CXBORDER);
+          else
+             Rect.left += rc.right /*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER);
+          Rect.top += rc.top - MENU_TOP_MARGIN;//3;
+          Rect.right = rc.left - rc.right + UserGetSystemMetrics(SM_CXBORDER);
+          Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/
+                                                     - UserGetSystemMetrics(SM_CYBORDER);
+      }
+      else
+      {
+          if(Flags & TPM_LAYOUTRTL)
+              Rect.left += Rect.right - Item->xItem; //ItemInfo.Rect.left;
+          else
+              Rect.left += Item->xItem; //ItemInfo.Rect.left;
+          Rect.top += Item->cyItem; //ItemInfo.Rect.bottom;
+          Rect.right  = Item->cxItem - Item->xItem; //ItemInfo.Rect.right - ItemInfo.Rect.left;
+          Rect.bottom = Item->cyItem - Item->yItem; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
+      }
+  }
+
+  /* use default alignment for submenus */
+  Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
+
+  MENU_InitPopup( WndOwner, Item->spSubMenu, Flags );
+
+  MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags,
+                Rect.left, Rect.top, Rect.right, Rect.bottom );
+  if (SelectFirst)
+  {
+      MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT);
+  }
+  return Item->spSubMenu;
+}
+
+/***********************************************************************
+ *           MenuExecFocusedItem
+ *
+ * Execute a menu item (for instance when user pressed Enter).
+ * Return the wID of the executed item. Otherwise, -1 indicating
+ * that no menu item was executed, -2 if a popup is shown;
+ * Have to receive the flags for the TrackPopupMenu options to avoid
+ * sending unwanted message.
+ *
+ */
+static INT FASTCALL MENU_ExecFocusedItem(MTRACKER *pmt, PMENU Menu, UINT Flags)
+{
+  PITEM Item;
+
+  TRACE("%p menu=%p\n", pmt, Menu);
+
+  if (!Menu || !Menu->cItems || Menu->iItem == NO_SELECTED_ITEM)
+  {
+      return -1;
+  }
+
+  Item = &Menu->rgItems[Menu->iItem];
+
+  TRACE("%p %08x %p\n", Menu, Item->wID, Item->spSubMenu);
+
+  if (!(Item->spSubMenu))
+  {
+      if (!(Item->fState & (MF_GRAYED | MF_DISABLED)) && !(Item->fType & MF_SEPARATOR))
+      {
+          /* If TPM_RETURNCMD is set you return the id, but
+            do not send a message to the owner */
+          if (!(Flags & TPM_RETURNCMD))
+          {
+              if (Menu->fFlags & MNF_SYSMENU)
+              {
+                  UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_SYSCOMMAND, Item->wID,
+                               MAKELPARAM((SHORT) pmt->Pt.x, (SHORT) pmt->Pt.y));
+              }
+              else
+              {
+                  DWORD dwStyle = ((Menu->fFlags & MNS_STYLE_MASK) | ( pmt->TopMenu ? (pmt->TopMenu->fFlags & MNS_STYLE_MASK) : 0) );
+
+                  if (dwStyle & MNS_NOTIFYBYPOS)
+                      UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_MENUCOMMAND, Menu->iItem, (LPARAM)UserHMGetHandle(Menu));
+                  else
+                      UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_COMMAND, Item->wID, 0);
+              }
+          }
+          return Item->wID;
+      }
+  }
+  else
+  {
+      pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, Menu, TRUE, Flags);
+      return -2;
+  }
+
+  return -1;
+}
+
+/***********************************************************************
+ *           MenuSwitchTracking
+ *
+ * Helper function for menu navigation routines.
+ */
+static void FASTCALL MENU_SwitchTracking(MTRACKER* pmt, PMENU PtMenu, UINT Index, UINT wFlags)
+{
+  TRACE("%x menu=%x 0x%04x\n", pmt, PtMenu, Index);
+
+  if ( pmt->TopMenu != PtMenu &&
+      !((PtMenu->fFlags | pmt->TopMenu->fFlags) & MNF_POPUP) )
+  {
+      /* both are top level menus (system and menu-bar) */
+      MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags);
+      MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, NULL);
+      pmt->TopMenu = PtMenu;
+  }
+  else
+  {
+      MENU_HideSubPopups(pmt->OwnerWnd, PtMenu, FALSE, wFlags);
+  }
+
+  MENU_SelectItem(pmt->OwnerWnd, PtMenu, Index, TRUE, NULL);
+}
+
+/***********************************************************************
+ *           MenuButtonDown
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL MENU_ButtonDown(MTRACKER* pmt, PMENU PtMenu, UINT Flags)
+{
+  TRACE("%x PtMenu=%p\n", pmt, PtMenu);
+
+  if (PtMenu)
+  {
+      UINT id = 0;
+      PITEM item;
+      if (IS_SYSTEM_MENU(PtMenu))
+      {
+         item = PtMenu->rgItems;
+      }
+      else
+      {
+         item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &id );
+      }
+
+      if (item)
+      {
+          if (PtMenu->iItem != id)
+              MENU_SwitchTracking(pmt, PtMenu, id, Flags);
+
+          /* If the popup menu is not already "popped" */
+          if (!(item->fState & MF_MOUSESELECT))
+          {
+              pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags);
+          }
+
+          return TRUE;
+      }
+      /* Else the click was on the menu bar, finish the tracking */
+  }
+  return FALSE;
+}
+
+/***********************************************************************
+ *           MenuButtonUp
+ *
+ * Return the value of MenuExecFocusedItem if
+ * the selected item was not a popup. Else open the popup.
+ * A -1 return value indicates that we go on with menu tracking.
+ *
+ */
+static INT FASTCALL MENU_ButtonUp(MTRACKER *pmt, PMENU PtMenu, UINT Flags)
+{
+  TRACE("%p pmenu=%x\n", pmt, PtMenu);
+
+  if (PtMenu)
+  {
+      UINT Id = 0;
+      ITEM *item;
+      
+      if ( IS_SYSTEM_MENU(PtMenu) )
+      {
+          item = PtMenu->rgItems;
+      }
+      else
+      {
+          item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &Id );
+      }
+
+      if (item && ( PtMenu->iItem == Id))
+      {
+          if (!(item->spSubMenu))
+          {
+              INT ExecutedMenuId = MENU_ExecFocusedItem( pmt, PtMenu, Flags);
+              if (ExecutedMenuId == -1 || ExecutedMenuId == -2) return -1;
+              return ExecutedMenuId;
+          }
+
+          /* If we are dealing with the menu bar                  */
+          /* and this is a click on an already "popped" item:     */
+          /* Stop the menu tracking and close the opened submenus */
+          if (pmt->TopMenu == PtMenu && PtMenu->TimeToHide)
+          {
+              return 0;
+          }
+      }
+      if ( IntGetMenu(PtMenu->hWnd) == PtMenu )
+      {
+          PtMenu->TimeToHide = TRUE;
+      }
+  }
+  return -1;
+}
+
+/***********************************************************************
+ *           MenuPtMenu
+ *
+ * Walks menu chain trying to find a menu pt maps to.
+ */
+static PMENU FASTCALL MENU_PtMenu(PMENU menu, POINT pt)
+{
+  PITEM pItem;
+  PMENU ret = NULL;
+
+  if (!menu) return NULL;
+
+  /* try subpopup first (if any) */
+  if (menu->iItem != NO_SELECTED_ITEM)
+  {
+     pItem = menu->rgItems;
+     if ( pItem ) pItem = &pItem[menu->iItem];
+     if ( pItem && pItem->spSubMenu && pItem->fState & MF_MOUSESELECT)
+     {
+        ret = MENU_PtMenu( pItem->spSubMenu, pt);
+     }
+  }
+
+  /* check the current window (avoiding WM_HITTEST) */
+  if (!ret)
+  {
+     PWND pWnd = ValidateHwndNoErr(menu->hWnd);
+     INT ht = GetNCHitEx(pWnd, pt);
+     if ( menu->fFlags & MNF_POPUP )
+     {
+        if (ht != HTNOWHERE && ht != HTERROR) ret = menu;
+     }
+     else if (ht == HTSYSMENU)
+        ret = get_win_sys_menu(menu->hWnd);
+     else if (ht == HTMENU)
+        ret = IntGetMenu( menu->hWnd );
+  }
+  return ret;
+}
+
+/***********************************************************************
+ *           MenuMouseMove
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL MENU_MouseMove(MTRACKER *pmt, PMENU PtMenu, UINT Flags)
+{
+  UINT Index = NO_SELECTED_ITEM;
+
+  if ( PtMenu )
+  {
+      if (IS_SYSTEM_MENU(PtMenu))
+          Index = 0;
+      else
+          MENU_FindItemByCoords( PtMenu, pmt->Pt, &Index );
+  }
+
+  if (Index == NO_SELECTED_ITEM)
+  {
+      MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NO_SELECTED_ITEM, TRUE, pmt->TopMenu);
+  }
+  else if (PtMenu->iItem != Index)
+  {
+      MENU_SwitchTracking(pmt, PtMenu, Index, Flags);
+      pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags);
+  }
+  return TRUE;
+}
+
+/***********************************************************************
+ *           MenuGetSubPopup
+ *
+ * Return the handle of the selected sub-popup menu (if any).
+ */
+static PMENU MENU_GetSubPopup( PMENU menu )
+{
+    ITEM *item;
+
+    if ((!menu) || (menu->iItem == NO_SELECTED_ITEM)) return 0;
+
+    item = &menu->rgItems[menu->iItem];
+    if (item && (item->spSubMenu) && (item->fState & MF_MOUSESELECT))
+    {
+       return item->spSubMenu;
+    }
+    return 0;
+}
+
+/***********************************************************************
+ *           MenuDoNextMenu
+ *
+ * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
+ */
+static LRESULT FASTCALL MENU_DoNextMenu(MTRACKER* pmt, UINT Vk, UINT wFlags)
+{
+    BOOL atEnd = FALSE;
+
+    /* When skipping left, we need to do something special after the
+       first menu.                                                  */
+    if (Vk == VK_LEFT && pmt->TopMenu->iItem == 0)
+    {
+        atEnd = TRUE;
+    }
+    /* When skipping right, for the non-system menu, we need to
+       handle the last non-special menu item (ie skip any window
+       icons such as MDI maximize, restore or close)             */
+    else if ((Vk == VK_RIGHT) && !IS_SYSTEM_MENU(pmt->TopMenu))
+    {
+        UINT i = pmt->TopMenu->iItem + 1;
+        while (i < pmt->TopMenu->cItems) {
+            if ((pmt->TopMenu->rgItems[i].wID >= SC_SIZE &&
+                 pmt->TopMenu->rgItems[i].wID <= SC_RESTORE)) {
+                i++;
+            } else break;
+        }
+        if (i == pmt->TopMenu->cItems) {
+            atEnd = TRUE;
+        }
+    }
+    /* When skipping right, we need to cater for the system menu */
+    else if ((Vk == VK_RIGHT) && IS_SYSTEM_MENU(pmt->TopMenu))
+    {
+        if (pmt->TopMenu->iItem == (pmt->TopMenu->cItems - 1)) {
+            atEnd = TRUE;
+        }
+    }
+
+   if ( atEnd )
+   {
+      MDINEXTMENU NextMenu;
+      PMENU MenuTmp;
+      PWND pwndTemp;
+      HMENU hNewMenu;
+      HWND hNewWnd;
+      UINT Id = 0;
+
+      MenuTmp = (IS_SYSTEM_MENU(pmt->TopMenu)) ? co_IntGetSubMenu(pmt->TopMenu, 0) : pmt->TopMenu;
+      NextMenu.hmenuIn = UserHMGetHandle(MenuTmp);
+      NextMenu.hmenuNext = NULL;
+      NextMenu.hwndNext = NULL;
+      co_IntSendMessage(UserHMGetHandle(pmt->OwnerWnd), WM_NEXTMENU, Vk, (LPARAM) &NextMenu);
+
+      TRACE("%p [%p] -> %p [%p]\n",
+             pmt->CurrentMenu, pmt->OwnerWnd, NextMenu.hmenuNext, NextMenu.hwndNext );
+
+      if (NULL == NextMenu.hmenuNext || NULL == NextMenu.hwndNext)
+      {
+          hNewWnd = UserHMGetHandle(pmt->OwnerWnd);
+          if (IS_SYSTEM_MENU(pmt->TopMenu))
+          {
+              /* switch to the menu bar */
+
+              if (pmt->OwnerWnd->style & WS_CHILD || !(MenuTmp = IntGetMenu(hNewWnd))) return FALSE;
+
+              if (Vk == VK_LEFT)
+              {
+                  Id = MenuTmp->cItems - 1;
+   
+                  /* Skip backwards over any system predefined icons,
+                     eg. MDI close, restore etc icons                 */
+                   while ((Id > 0) &&
+                          (MenuTmp->rgItems[Id].wID >= SC_SIZE &&
+                           MenuTmp->rgItems[Id].wID <= SC_RESTORE)) Id--;
+              }
+              hNewMenu = UserHMGetHandle(MenuTmp);
+          }
+          else if (pmt->OwnerWnd->style & WS_SYSMENU)
+          {
+              /* switch to the system menu */
+              MenuTmp = get_win_sys_menu(hNewWnd);
+              hNewMenu = UserHMGetHandle(MenuTmp);
+          }
+          else
+              return FALSE;
+      }
+      else    /* application returned a new menu to switch to */
+      {
+          hNewMenu = NextMenu.hmenuNext;
+          hNewWnd = NextMenu.hwndNext;
+
+          if ((MenuTmp = UserGetMenuObject(hNewMenu)) && (pwndTemp = ValidateHwndNoErr(hNewWnd)))
+          {
+              if ( pwndTemp->style & WS_SYSMENU && (get_win_sys_menu(hNewWnd) == MenuTmp) )
+              {
+                  /* get the real system menu */
+                  MenuTmp = get_win_sys_menu(hNewWnd);
+                  hNewMenu = UserHMGetHandle(MenuTmp);
+              }
+              else if (pwndTemp->style & WS_CHILD || IntGetMenu(hNewWnd) != MenuTmp)
+              {
+                  /* FIXME: Not sure what to do here;
+                   * perhaps try to track NewMenu as a popup? */
+
+                  WARN(" -- got confused.\n");
+                  return FALSE;
+              }
+          }
+          else return FALSE;
+      }
+
+      if (hNewMenu != UserHMGetHandle(pmt->TopMenu))
+      {
+          MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, 0 );
+
+          if (pmt->CurrentMenu != pmt->TopMenu)
+              MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags);
+      }
+
+      if (hNewWnd != UserHMGetHandle(pmt->OwnerWnd))
+      {
+          PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+          pmt->OwnerWnd = ValidateHwndNoErr(hNewWnd);
+          ///// Use thread pms!!!!
+          MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, hNewWnd);
+          pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
+          co_UserSetCapture(UserHMGetHandle(pmt->OwnerWnd));
+          pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED;
+      }
+
+      pmt->TopMenu = pmt->CurrentMenu = UserGetMenuObject(hNewMenu); /* all subpopups are hidden */
+      MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, Id, TRUE, 0);
+
+      return TRUE;
+   }
+   return FALSE;
+}
+
+/***********************************************************************
+ *           MenuSuspendPopup
+ *
+ * The idea is not to show the popup if the next input message is
+ * going to hide it anyway.
+ */
+static BOOL FASTCALL MENU_SuspendPopup(MTRACKER* pmt, UINT uMsg)
+{
+    MSG msg;
+
+    msg.hwnd = UserHMGetHandle(pmt->OwnerWnd); ////// ? silly wine'isms?
+
+    co_IntGetPeekMessage( &msg, 0, uMsg, uMsg, PM_NOYIELD | PM_REMOVE, FALSE);
+    pmt->TrackFlags |= TF_SKIPREMOVE;
+
+    switch( uMsg )
+    {
+    case WM_KEYDOWN:
+        co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE);
+        if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
+        {
+            co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE, FALSE);
+            co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE);
+            if( msg.message == WM_KEYDOWN &&
+                (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
+            {
+                 pmt->TrackFlags |= TF_SUSPENDPOPUP;
+                 return TRUE;
+            }
+        }
+        break;
+    }
+    /* failures go through this */
+    pmt->TrackFlags &= ~TF_SUSPENDPOPUP;
+    return FALSE;
+}
+
+/***********************************************************************
+ *           MenuKeyEscape
+ *
+ * Handle a VK_ESCAPE key event in a menu.
+ */
+static BOOL FASTCALL MENU_KeyEscape(MTRACKER *pmt, UINT Flags)
+{
+  BOOL EndMenu = TRUE;
+
+  if (pmt->CurrentMenu != pmt->TopMenu)
+  {
+      if (pmt->CurrentMenu && (pmt->CurrentMenu->fFlags & MNF_POPUP))
+      {
+          PMENU MenuPrev, MenuTmp;
+
+          MenuPrev = MenuTmp = pmt->TopMenu;
+
+          /* close topmost popup */
+          while (MenuTmp != pmt->CurrentMenu)
+          {
+              MenuPrev = MenuTmp;
+              MenuTmp = MENU_GetSubPopup(MenuPrev);
+          }
+
+          MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags);
+          pmt->CurrentMenu = MenuPrev;
+          EndMenu = FALSE;
+      }
+  }
+
+  return EndMenu;
+}
+
+/***********************************************************************
+ *           MenuKeyLeft
+ *
+ * Handle a VK_LEFT key event in a menu.
+ */
+static void FASTCALL MENU_KeyLeft(MTRACKER* pmt, UINT Flags)
+{
+  PMENU MenuTmp, MenuPrev;
+  UINT PrevCol;
+
+  MenuPrev = MenuTmp = pmt->TopMenu;
+
+  /* Try to move 1 column left (if possible) */
+  if ( (PrevCol = MENU_GetStartOfPrevColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM)
+  {
+     MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, PrevCol, TRUE, 0);
+     return;
+  }
+
+  /* close topmost popup */
+  while (MenuTmp != pmt->CurrentMenu)
+  {
+      MenuPrev = MenuTmp;
+      MenuTmp = MENU_GetSubPopup(MenuPrev);
+  }
+
+  MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags);
+  pmt->CurrentMenu = MenuPrev;
+
+  if ((MenuPrev == pmt->TopMenu) && !(pmt->TopMenu->fFlags & MNF_POPUP))
+  {
+      /* move menu bar selection if no more popups are left */
+
+      if (!MENU_DoNextMenu(pmt, VK_LEFT, Flags))
+          MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_PREV);
+
+      if (MenuPrev != MenuTmp || pmt->TrackFlags & TF_SUSPENDPOPUP)
+      {
+          /* A sublevel menu was displayed - display the next one
+           * unless there is another displacement coming up */
+
+          if (!MENU_SuspendPopup(pmt, WM_KEYDOWN))
+              pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu,
+                                                 TRUE, Flags);
+      }
+  }
+}
+
+/***********************************************************************
+ *           MenuKeyRight
+ *
+ * Handle a VK_RIGHT key event in a menu.
+ */
+static void FASTCALL MENU_KeyRight(MTRACKER *pmt, UINT Flags)
+{
+    PMENU menutmp;
+    UINT NextCol;
+
+    TRACE("MenuKeyRight called, cur %p, top %p.\n",
+         pmt->CurrentMenu, pmt->TopMenu);
+
+    if ((pmt->TopMenu->fFlags & MNF_POPUP) || (pmt->CurrentMenu != pmt->TopMenu))
+    {
+      /* If already displaying a popup, try to display sub-popup */
+
+      menutmp = pmt->CurrentMenu;
+      pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, menutmp, TRUE, Flags);
+
+      /* if subpopup was displayed then we are done */
+      if (menutmp != pmt->CurrentMenu) return;
+    }
+
+    /* Check to see if there's another column */
+    if ( (NextCol = MENU_GetStartOfNextColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM)
+    {
+       TRACE("Going to %d.\n", NextCol);
+       MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NextCol, TRUE, 0);
+       return;
+    }
+
+    if (!(pmt->TopMenu->fFlags & MNF_POPUP)) /* menu bar tracking */
+    {
+       if (pmt->CurrentMenu != pmt->TopMenu)
+       {
+          MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, Flags);
+          menutmp = pmt->CurrentMenu = pmt->TopMenu;
+       }
+       else
+       {
+          menutmp = NULL;
+       }
+
+       /* try to move to the next item */
+       if ( !MENU_DoNextMenu(pmt, VK_RIGHT, Flags))
+           MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_NEXT);
+
+       if ( menutmp || pmt->TrackFlags & TF_SUSPENDPOPUP )
+       {
+           if ( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
+               pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu, TRUE, Flags);
+       }
+    }
+}
+
+/***********************************************************************
+ *           MenuTrackMenu
+ *
+ * Menu tracking code.
+ */
+static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
+                            PWND pwnd, const RECT *lprect )
+{
+    MSG msg;
+    BOOL fRemove;
+    INT executedMenuId = -1;
+    MTRACKER mt;
+    HWND capture_win;
+    PMENU pmMouse;
+    BOOL enterIdleSent = FALSE;
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+    if (pti != pwnd->head.pti)
+    {
+       ERR("Not the same PTI!!!!\n");
+    }
+
+    mt.TrackFlags = 0;
+    mt.CurrentMenu = pmenu;
+    mt.TopMenu = pmenu;
+    mt.OwnerWnd = pwnd;
+    mt.Pt.x = x;
+    mt.Pt.y = y;
+
+    TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
+         UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd), lprect ? lprect->left : 0, lprect ? lprect->top : 0,
+         lprect ? lprect->right : 0, lprect ? lprect->bottom : 0);
+
+    pti->MessageQueue->QF_flags &= ~QF_ACTIVATIONCHANGE;
+
+    if (wFlags & TPM_BUTTONDOWN)
+    {
+        /* Get the result in order to start the tracking or not */
+        fRemove = MENU_ButtonDown( &mt, pmenu, wFlags );
+        fInsideMenuLoop = fRemove;
+    }
+
+    if (wFlags & TF_ENDMENU) fInsideMenuLoop = FALSE;
+
+    if (wFlags & TPM_POPUPMENU && pmenu->cItems == 0) // Tracking empty popup menu...
+    {
+       MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
+       pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
+       co_UserSetCapture(NULL); /* release the capture */
+       return 0;
+    }
+
+    capture_win = IntGetCapture();
+
+    while (fInsideMenuLoop)
+    {
+        BOOL ErrorExit = FALSE;
+        if (!VerifyMenu( mt.CurrentMenu )) /* sometimes happens if I do a window manager close */
+           break;
+
+        /* we have to keep the message in the queue until it's
+         * clear that menu loop is not over yet. */
+
+        for (;;)
+        {
+            if (co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOREMOVE, FALSE ))
+            {
+                if (!IntCallMsgFilter( &msg, MSGF_MENU )) break;
+                /* remove the message from the queue */
+                co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
+            }
+            else
+            {
+                /* ReactOS Checks */
+                if (!VerifyWnd(mt.OwnerWnd)                            ||
+                    !ValidateHwndNoErr(mt.CurrentMenu->hWnd)           ||
+                     pti->MessageQueue->QF_flags & QF_ACTIVATIONCHANGE ||
+                     capture_win != IntGetCapture() ) // Should not happen, but this is ReactOS...
+                {
+                   ErrorExit = TRUE; // Do not wait on dead windows, now win test_capture_4 works.
+                   break;
+                }
+
+                if (!enterIdleSent)
+                {
+                  HWND win = mt.CurrentMenu->fFlags & MNF_POPUP ? mt.CurrentMenu->hWnd : NULL;
+                  enterIdleSent = TRUE;
+                  co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_ENTERIDLE, MSGF_MENU, (LPARAM) win);
+                }
+                co_IntWaitMessage(NULL, 0, 0);
+            }
+        }
+
+        if (ErrorExit) break; // Gracefully dropout.
+
+        /* check if EndMenu() tried to cancel us, by posting this message */
+        if (msg.message == WM_CANCELMODE)
+        {
+            /* we are now out of the loop */
+            fInsideMenuLoop = FALSE;
+
+            /* remove the message from the queue */
+            co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
+
+            /* break out of internal loop, ala ESCAPE */
+            break;
+        }
+
+        IntTranslateKbdMessage(&msg, 0);
+        mt.Pt = msg.pt;
+
+        if ( (msg.hwnd == mt.CurrentMenu->hWnd) || ((msg.message!=WM_TIMER) || (msg.message!=WM_SYSTIMER)) )
+            enterIdleSent=FALSE;
+
+        fRemove = FALSE;
+        if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
+        {
+            /*
+             * Use the mouse coordinates in lParam instead of those in the MSG
+             * struct to properly handle synthetic messages. They are already
+             * in screen coordinates.
+             */
+            mt.Pt.x = (short)LOWORD(msg.lParam);
+            mt.Pt.y = (short)HIWORD(msg.lParam);
+
+            /* Find a menu for this mouse event */
+            pmMouse = MENU_PtMenu( mt.TopMenu, mt.Pt );
+
+            switch(msg.message)
+            {
+                /* no WM_NC... messages in captured state */
+
+                case WM_RBUTTONDBLCLK:
+                case WM_RBUTTONDOWN:
+                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
+                    /* fall through */
+                case WM_LBUTTONDBLCLK:
+                case WM_LBUTTONDOWN:
+                    /* If the message belongs to the menu, removes it from the queue */
+                    /* Else, end menu tracking */
+                    fRemove = MENU_ButtonDown(&mt, pmMouse, wFlags);
+                    fInsideMenuLoop = fRemove;
+                    if (msg.message == WM_LBUTTONDBLCLK) fInsideMenuLoop = FALSE; // Must exit or loop forever!
+                    break;
+
+                case WM_RBUTTONUP:
+                    if (!(wFlags & TPM_RIGHTBUTTON)) break;
+                    /* fall through */
+                case WM_LBUTTONUP:
+                    /* Check if a menu was selected by the mouse */
+                    if (pmMouse)
+                    {
+                        executedMenuId = MENU_ButtonUp( &mt, pmMouse, wFlags);
+
+                    /* End the loop if executedMenuId is an item ID */
+                    /* or if the job was done (executedMenuId = 0). */
+                        fRemove = (executedMenuId != -1);
+                        fInsideMenuLoop = !fRemove;
+                    }
+                    /* No menu was selected by the mouse */
+                    /* if the function was called by TrackPopupMenu, continue
+                       with the menu tracking. If not, stop it */
+                    else
+                        fInsideMenuLoop = ((wFlags & TPM_POPUPMENU) ? TRUE : FALSE);
+
+                    break;
+
+                case WM_MOUSEMOVE:
+                    /* the selected menu item must be changed every time */
+                    /* the mouse moves. */
+
+                    if (pmMouse)
+                        fInsideMenuLoop |= MENU_MouseMove( &mt, pmMouse, wFlags );
+
+           } /* switch(msg.message) - mouse */
+        }
+        else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
+        {
+            fRemove = TRUE;  /* Keyboard messages are always removed */
+            switch(msg.message)
+            {
+                case WM_KEYDOWN:
+                case WM_SYSKEYDOWN:
+                switch(msg.wParam)
+                {
+                    case VK_MENU:
+                    case VK_F10:
+                        fInsideMenuLoop = FALSE;
+                        break;
+
+                    case VK_HOME:
+                    case VK_END:
+                        MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, NO_SELECTED_ITEM, FALSE, 0 );
+                        MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV);
+                        break;
+
+                    case VK_UP:
+                    case VK_DOWN: /* If on menu bar, pull-down the menu */
+                        if (!(mt.CurrentMenu->fFlags & MNF_POPUP))
+                            mt.CurrentMenu = MENU_ShowSubPopup(mt.OwnerWnd, mt.TopMenu, TRUE, wFlags);
+                        else      /* otherwise try to move selection */
+                            MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
+                        break;
+
+                    case VK_LEFT:
+                        MENU_KeyLeft( &mt, wFlags );
+                        break;
+
+                    case VK_RIGHT:
+                        MENU_KeyRight( &mt, wFlags );
+                        break;
+
+                    case VK_ESCAPE:
+                        fInsideMenuLoop = !MENU_KeyEscape(&mt, wFlags);
+                        break;
+
+                    case VK_F1:
+                    {
+                        HELPINFO hi;
+                        hi.cbSize = sizeof(HELPINFO);
+                        hi.iContextType = HELPINFO_MENUITEM;
+                        if (mt.CurrentMenu->iItem == NO_SELECTED_ITEM)
+                            hi.iCtrlId = 0;
+                        else
+                            hi.iCtrlId = pmenu->rgItems[mt.CurrentMenu->iItem].wID;
+                        hi.hItemHandle = UserHMGetHandle(mt.CurrentMenu);
+                        hi.dwContextId = pmenu->dwContextHelpId;
+                        hi.MousePos = msg.pt;
+                        co_IntSendMessage( UserHMGetHandle(pwnd), WM_HELP, 0, (LPARAM)&hi);
+                        break;
+                    }
+
+                    default:
+                        break;
+                }
+                break;  /* WM_KEYDOWN */
+
+                case WM_CHAR:
+                case WM_SYSCHAR:
+                {
+                    UINT pos;
+                    BOOL fEndMenu;
+
+                    if (msg.wParam == L'\r' || msg.wParam == L' ')
+                    {
+                        executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags);
+                        fEndMenu = (executedMenuId != -2);
+                        fInsideMenuLoop = !fEndMenu;
+                        break;
+                    }
+
+                    /* Hack to avoid control chars. */
+                    /* We will find a better way real soon... */
+                    if (msg.wParam < 32) break;
+
+                    pos = MENU_FindItemByKey(mt.OwnerWnd, mt.CurrentMenu, LOWORD(msg.wParam), FALSE);
+
+                    if (pos == (UINT)-2) fInsideMenuLoop = FALSE;
+                    else if (pos == (UINT)-1) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0);
+                    else
+                    {
+                        MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, pos, TRUE, 0);
+                        executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags);
+                        fEndMenu = (executedMenuId != -2);
+                        fInsideMenuLoop = !fEndMenu;
+                    }
+                }
+                break;
+            }  /* switch(msg.message) - kbd */
+        }
+        else
+        {
+            co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
+            IntDispatchMessage( &msg );
+            continue;
+        }
+
+        if (fInsideMenuLoop) fRemove = TRUE;
+
+        /* finally remove message from the queue */
+
+        if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) )
+            co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
+        else mt.TrackFlags &= ~TF_SKIPREMOVE;
+    }
+
+    MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
+    pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
+    co_UserSetCapture(NULL); /* release the capture */
+
+    /* If dropdown is still painted and the close box is clicked on
+       then the menu will be destroyed as part of the DispatchMessage above.
+       This will then invalidate the menu handle in mt.hTopMenu. We should
+       check for this first.  */
+    if ( VerifyMenu( mt.TopMenu ) )
+    {
+       if (VerifyWnd(mt.OwnerWnd))
+       {
+           MENU_HideSubPopups(mt.OwnerWnd, mt.TopMenu, FALSE, wFlags);
+
+           if (mt.TopMenu->fFlags & MNF_POPUP)
+           {
+              PWND pwndTM = ValidateHwndNoErr(mt.TopMenu->hWnd);
+              IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, pwndTM, OBJID_CLIENT, CHILDID_SELF, 0);
+
+              co_UserDestroyWindow(pwndTM);
+              mt.TopMenu->hWnd = NULL;
+
+              if (!(wFlags & TPM_NONOTIFY))
+              {
+                 co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(mt.TopMenu),
+                                 MAKELPARAM(0, IS_SYSTEM_MENU(mt.TopMenu)) );
+              }
+            }
+            MENU_SelectItem( mt.OwnerWnd, mt.TopMenu, NO_SELECTED_ITEM, FALSE, 0 );
+            co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 );
+       }
+
+       /* Reset the variable for hiding menu */
+       mt.TopMenu->TimeToHide = FALSE;
+    }
+
+    /* The return value is only used by TrackPopupMenu */
+    if (!(wFlags & TPM_RETURNCMD)) return TRUE;
+    if (executedMenuId == -1) executedMenuId = 0;
+    return executedMenuId;
+}
+
+/***********************************************************************
+ *           MenuInitTracking
+ */
+static BOOL FASTCALL MENU_InitTracking(PWND pWnd, PMENU Menu, BOOL bPopup, UINT wFlags)
+{
+    HWND capture_win;
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+    TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd), UserHMGetHandle(Menu));
+
+    co_UserHideCaret(0);
+
+    /* This makes the menus of applications built with Delphi work.
+     * It also enables menus to be displayed in more than one window,
+     * but there are some bugs left that need to be fixed in this case.
+     */
+    if (!bPopup)
+    {
+        Menu->hWnd = UserHMGetHandle(pWnd);
+    }
+
+    if (!top_popup) {
+       top_popup = Menu->hWnd;
+       top_popup_hmenu = UserHMGetHandle(Menu);
+    }
+
+    fInsideMenuLoop = TRUE;
+    fInEndMenu = FALSE;
+
+    /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
+    if (!(wFlags & TPM_NONOTIFY))
+    {
+       co_IntSendMessage( UserHMGetHandle(pWnd), WM_ENTERMENULOOP, bPopup, 0 );
+    }
+
+    //
+    // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
+    //
+    capture_win = (wFlags & TPM_POPUPMENU) ? Menu->hWnd : UserHMGetHandle(pWnd);
+    MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, capture_win); // 1
+    co_UserSetCapture(capture_win);                           // 2
+    pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED; // Set the Q bits so noone can change this!
+
+    co_IntSendMessage( UserHMGetHandle(pWnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(pWnd), HTCAPTION );
+
+    if (!(wFlags & TPM_NONOTIFY))
+    {
+       co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENU, (WPARAM)UserHMGetHandle(Menu), 0 );
+       /* If an app changed/recreated menu bar entries in WM_INITMENU
+        * menu sizes will be recalculated once the menu created/shown.
+        */
+    }
+
+    IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART,
+                       pWnd,
+                       Menu->fFlags & MNF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU,
+                       CHILDID_SELF, 0);
+    return TRUE;
+}
+
+/***********************************************************************
+ *           MenuExitTracking
+ */
+static BOOL FASTCALL MENU_ExitTracking(PWND pWnd, BOOL bPopup, UINT wFlags)
+{
+    TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd), bPopup);
+
+    IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
+
+    if (!(wFlags & TPM_NONOTIFY))
+       co_IntSendMessage( UserHMGetHandle(pWnd), WM_EXITMENULOOP, bPopup, 0 );
+
+    co_UserShowCaret(0);
+
+    top_popup = 0;
+    top_popup_hmenu = NULL;
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *           MenuTrackMouseMenuBar
+ *
+ * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
+ */
+VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt)
+{
+    PMENU pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) : IntGetMenu( UserHMGetHandle(pWnd) );
+    UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+
+    TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd, ht, pt.x, pt.y);
+
+    if (pWnd->ExStyle & WS_EX_LAYOUTRTL) wFlags |= TPM_LAYOUTRTL;
+    if (VerifyMenu(pMenu))
+    {
+        /* map point to parent client coordinates */
+        PWND Parent = UserGetAncestor(pWnd, GA_PARENT );
+        if (Parent != UserGetDesktopWindow())
+        {
+            IntScreenToClient(Parent, &pt);
+        }
+
+        MENU_InitTracking(pWnd, pMenu, FALSE, wFlags);
+        /* fetch the window menu again, it may have changed */
+        pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) : IntGetMenu( UserHMGetHandle(pWnd) );
+        MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd, NULL);
+        MENU_ExitTracking(pWnd, FALSE, wFlags);
+    }
+}
+
+/***********************************************************************
+ *           MenuTrackKbdMenuBar
+ *
+ * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
+ */
+VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar)
+{
+    UINT uItem = NO_SELECTED_ITEM;
+    PMENU TrackMenu;
+    UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON;
+
+    TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd), wParam, wChar);
+
+    /* find window that has a menu */
+
+    while (!( (pwnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD ) )
+        if (!(pwnd = UserGetAncestor( pwnd, GA_PARENT ))) return;
+
+    /* check if we have to track a system menu */
+
+    TrackMenu = IntGetMenu( UserHMGetHandle(pwnd) );
+    if (!TrackMenu || (pwnd->style & WS_MINIMIZE) != 0 || wChar == ' ' )
+    {
+        if (!(pwnd->style & WS_SYSMENU)) return;
+        TrackMenu = get_win_sys_menu( UserHMGetHandle(pwnd) );
+        uItem = 0;
+        wParam |= HTSYSMENU; /* prevent item lookup */
+    }
+
+    if (!VerifyMenu( TrackMenu )) return;
+
+    MENU_InitTracking( pwnd, TrackMenu, FALSE, wFlags );
+
+    /* fetch the window menu again, it may have changed */
+    TrackMenu = (wParam & HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pwnd) ) : IntGetMenu( UserHMGetHandle(pwnd) );
+
+    if( wChar && wChar != ' ' )
+    {
+        uItem = MENU_FindItemByKey( pwnd, TrackMenu, wChar, (wParam & HTSYSMENU) );
+        if ( uItem >= (UINT)(-2) )
+        {
+            if( uItem == (UINT)(-1) ) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0);
+            /* schedule end of menu tracking */
+            wFlags |= TF_ENDMENU;
+            goto track_menu;
+        }
+    }
+
+    MENU_SelectItem( pwnd, TrackMenu, uItem, TRUE, 0 );
+
+    if (!(wParam & HTSYSMENU) || wChar == ' ')
+    {
+        if( uItem == NO_SELECTED_ITEM )
+            MENU_MoveSelection( pwnd, TrackMenu, ITEM_NEXT );
+        else
+            UserPostMessage( UserHMGetHandle(pwnd), WM_KEYDOWN, VK_RETURN, 0 );
+    }
+
+track_menu:
+    MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd, NULL );
+    MENU_ExitTracking( pwnd, FALSE, wFlags);
+}
+
+/**********************************************************************
+ *           TrackPopupMenuEx   (USER32.@)
+ */
+BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int y,
+                              PWND pWnd, LPTPMPARAMS lpTpm)
+{
+    BOOL ret = FALSE;
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+    if (pti != pWnd->head.pti)
+    {
+       ERR("Must be the same pti!\n");
+       return ret;
+    }
+
+    TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
+            UserHMGetHandle(menu), wFlags, x, y, UserHMGetHandle(pWnd), lpTpm); //,
+            //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
+
+    if (menu->hWnd && IntIsWindow(menu->hWnd))
+    {
+        EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE );
+        return FALSE;
+    }
+
+    if (MENU_InitPopup( pWnd, menu, wFlags ))
+    {
+       MENU_InitTracking(pWnd, menu, TRUE, wFlags);
+
+       /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+       if (!(wFlags & TPM_NONOTIFY))
+       {
+          co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENUPOPUP, (WPARAM) UserHMGetHandle(menu), 0);
+       }
+
+       if (MENU_ShowPopup(pWnd, menu, 0, wFlags, x, y, 0, 0 ))
+          ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd,
+                                lpTpm ? &lpTpm->rcExclude : NULL);
+       else
+       {
+          MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
+          pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
+          co_UserSetCapture(NULL); /* release the capture */
+       }
+
+       //
+       // HACK : Until back trace fault in co_IntUpdateWindows and MENU_TrackMenu.
+       //
+       if (EngGetLastError() == ERROR_ACCESS_DENIED)
+       {
+          EngSetLastError(NO_ERROR);
+       }
+
+       MENU_ExitTracking(pWnd, TRUE, wFlags);
+
+       if (menu->hWnd)
+       {
+          PWND pwndM = ValidateHwndNoErr( menu->hWnd );
+          if (pwndM) // wine hack around this with their destroy function.
+             co_UserDestroyWindow( pwndM ); // Fix wrong error return.
+          menu->hWnd = 0;
+
+          if (!(wFlags & TPM_NONOTIFY))
+          {
+             co_IntSendMessage( UserHMGetHandle(pWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(menu),
+                                            MAKELPARAM(0, IS_SYSTEM_MENU(menu)) );
+          }
+       }
+    }
+    return ret;
+}
+
+//
+// Menu Class Proc.
+//
+BOOL WINAPI
+PopupMenuWndProc(
+   PWND Wnd,
+   UINT Message,
+   WPARAM wParam,
+   LPARAM lParam,
+   LRESULT *lResult)
+{
+  PPOPUPMENU pPopupMenu;
+
+  *lResult = 0;
+
+  TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+  if (Wnd)
+  {
+     if (!Wnd->fnid)
+     {
+        if (Message != WM_NCCREATE)
+        {
+           *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE);
+           return TRUE;
+        }
+        Wnd->fnid = FNID_MENU;
+        pPopupMenu = DesktopHeapAlloc( Wnd->head.rpdesk, sizeof(POPUPMENU) );
+        pPopupMenu->posSelectedItem = NO_SELECTED_ITEM;
+        pPopupMenu->spwndPopupMenu = Wnd;
+        ((PMENUWND)Wnd)->ppopupmenu = pPopupMenu;
+        TRACE("Pop Up Menu is Setup! Msg %d\n",Message);
+        *lResult = 1;
+        return TRUE;
+     }
+     else
+     {
+        if (Wnd->fnid != FNID_MENU)
+        {
+           ERR("Wrong window class for Menu! fnid %x\n",Wnd->fnid);
+           return TRUE;
+        }
+        pPopupMenu = ((PMENUWND)Wnd)->ppopupmenu;
+     }
+  }
+
+  switch(Message)
+    {
+    case WM_CREATE:
+      {
+        CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
+        pPopupMenu->spmenu = UserGetMenuObject(cs->lpCreateParams);
+        break;
+      }
+
+    case WM_MOUSEACTIVATE:  /* We don't want to be activated */
+      *lResult = MA_NOACTIVATE;
+      break;
+
+    case WM_PAINT:
+      {
+        PAINTSTRUCT ps;
+        IntBeginPaint(Wnd, &ps);
+        MENU_DrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu);
+        IntEndPaint(Wnd, &ps);
+        break;
+      }
+
+    case WM_PRINTCLIENT:
+      {
+         MENU_DrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu);
+         break;
+      }
+
+    case WM_ERASEBKGND:
+      *lResult = 1;
+      break;
+
+    case WM_DESTROY:
+      /* zero out global pointer in case resident popup window was destroyed. */
+      if (pPopupMenu)
+      {
+         if (UserHMGetHandle(Wnd) == top_popup)
+         {
+             top_popup = NULL;
+             top_popup_hmenu = NULL;
+         }
+      }
+      else
+      {
+         ERR("No Window Pop Up!\n");
+      }
+      break;
+
+    case WM_NCDESTROY:
+      {
+         DesktopHeapFree(Wnd->head.rpdesk, pPopupMenu );
+         ((PMENUWND)Wnd)->ppopupmenu = 0;
+         Wnd->fnid = FNID_DESTROY;
+         break;
+      }
+
+    case MM_SETMENUHANDLE: // wine'isms
+    case MN_SETHMENU:
+      {
+        PMENU pmenu = UserGetMenuObject((HMENU)wParam);
+        if (!pmenu)
+        {
+           ERR("Bad Menu Handle\n");
+           break;
+        }
+        pPopupMenu->spmenu = pmenu;
+        break;
+      }
+
+    case MM_GETMENUHANDLE: // wine'isms
+    case MN_GETHMENU:
+         *lResult = (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? UserHMGetHandle(pPopupMenu->spmenu) : NULL) : NULL);
+         break;
+
+    default:
+      if (Message > MN_GETHMENU && Message < MN_GETHMENU+19)
+      {
+         ERR("Someone is passing unknown menu messages %d\n",Message);
+      }
+      TRACE("PMWP to IDWP %d\n",Message);
+      *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE);
+      break;
+    }
 
-   return res;
+  return TRUE;
 }
 
 BOOL FASTCALL
@@ -1026,8 +4508,9 @@ IntHiliteMenuItem(PWND WindowObject,
                   UINT uHilite)
 {
    PITEM MenuItem;
+   UINT uItem = uItemHilite;
 
-   if (!(MenuItem = MENU_FindItem( &MenuObject, &uItemHilite, uHilite ))) return FALSE;
+   if (!(MenuItem = MENU_FindItem( &MenuObject, &uItem, uHilite ))) return TRUE;
 
    if (uHilite & MF_HILITE)
    {
@@ -1037,127 +4520,13 @@ IntHiliteMenuItem(PWND WindowObject,
    {
       MenuItem->fState &= ~MF_HILITE;
    }
-   /* FIXME: Update the window's menu */
+   if (MenuObject->iItem == uItemHilite) return TRUE;
+   MENU_HideSubPopups( WindowObject, MenuObject, FALSE, 0 );
+   MENU_SelectItem( WindowObject, MenuObject, uItemHilite, TRUE, 0 );
 
    return TRUE; // Always returns true!!!!
 }
 
-BOOL FASTCALL
-UserSetMenuDefaultItem(PMENU MenuObject, UINT uItem, UINT fByPos)
-{
-   UINT i;
-   PITEM MenuItem = MenuObject->rgItems;
-
-   if (!MenuItem) return FALSE;
-
-   /* reset all default-item flags */
-   for (i = 0; i < MenuObject->cItems; i++, MenuItem++)
-   {
-       MenuItem->fState &= ~MFS_DEFAULT;
-   }
-
-   /* no default item */
-   if(uItem == (UINT)-1)
-   {
-      return TRUE;
-   }
-   MenuItem = MenuObject->rgItems;
-   if ( fByPos )
-   {
-      if ( uItem >= MenuObject->cItems ) return FALSE;
-         MenuItem[uItem].fState |= MFS_DEFAULT;
-      return TRUE;
-   }
-   else
-   {
-      for (i = 0; i < MenuObject->cItems; i++, MenuItem++)
-      {
-          if (MenuItem->wID == uItem)
-          {
-             MenuItem->fState |= MFS_DEFAULT;
-             return TRUE;
-          }
-      }
-
-   }
-   return FALSE;
-}
-
-
-UINT FASTCALL
-IntGetMenuDefaultItem(PMENU MenuObject, UINT fByPos, UINT gmdiFlags, DWORD *gismc)
-{
-   UINT i = 0;
-   PITEM MenuItem = MenuObject->rgItems;
-
-   /* empty menu */
-   if (!MenuItem) return -1;
-
-   while ( !( MenuItem->fState & MFS_DEFAULT ) )
-   {
-      i++; MenuItem++;
-      if  (i >= MenuObject->cItems ) return -1;
-   }
-
-   /* default: don't return disabled items */
-   if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (MenuItem->fState & MFS_DISABLED )) return -1;
-
-   /* search rekursiv when needed */
-   if ( (MenuItem->fType & MF_POPUP) && (gmdiFlags & GMDI_GOINTOPOPUPS) && MenuItem->spSubMenu)
-   {
-      UINT ret;
-      (*gismc)++;
-      ret = IntGetMenuDefaultItem( MenuItem->spSubMenu, fByPos, gmdiFlags, gismc );
-      (*gismc)--;
-      if ( -1 != ret ) return ret;
-
-      /* when item not found in submenu, return the popup item */
-   }
-   return ( fByPos ) ? i : MenuItem->wID;
-}
-
-VOID FASTCALL
-co_IntInitTracking(PWND Window, PMENU Menu, BOOL Popup,
-                   UINT Flags)
-{
-   /* FIXME: Hide caret */
-
-   if(!(Flags & TPM_NONOTIFY))
-      co_IntSendMessage(Window->head.h, WM_SETCURSOR, (WPARAM)Window->head.h, HTCAPTION);
-
-   /* FIXME: Send WM_SETCURSOR message */
-
-   if(!(Flags & TPM_NONOTIFY))
-      co_IntSendMessage(Window->head.h, WM_INITMENU, (WPARAM)Menu->head.h, 0);
-}
-
-VOID FASTCALL
-co_IntExitTracking(PWND Window, PMENU Menu, BOOL Popup,
-                   UINT Flags)
-{
-   if(!(Flags & TPM_NONOTIFY))
-      co_IntSendMessage(Window->head.h, WM_EXITMENULOOP, 0 /* FIXME */, 0);
-
-   /* FIXME: Show caret again */
-}
-
-INT FASTCALL
-IntTrackMenu(PMENU Menu, PWND Window, INT x, INT y,
-             RECTL lprect)
-{
-   return 0;
-}
-
-BOOL FASTCALL
-co_IntTrackPopupMenu(PMENU Menu, PWND Window,
-                     UINT Flags, POINT *Pos, UINT MenuPos, RECTL *ExcludeRect)
-{
-   co_IntInitTracking(Window, Menu, TRUE, Flags);
-
-   co_IntExitTracking(Window, Menu, TRUE, Flags);
-   return FALSE;
-}
-
 BOOLEAN APIENTRY
 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
 {
@@ -1372,39 +4741,18 @@ HMENU FASTCALL IntGetSubMenu( HMENU hMenu, int nPos)
 
 UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
 {
-    PMENU menu;
-    HMENU hSubMenu;
-    UINT i;
-    PITEM item;
-
+    PMENU menu, pSubTarget;
+    UINT Pos;
     if (((*hMenu)==(HMENU)0xffff) ||(!(menu = UserGetMenuObject(*hMenu))))
         return NO_SELECTED_ITEM;
 
-    item = menu->rgItems;
-    for (i = 0; i < menu->cItems; i++, item++)
-    {
-        if (!item->spSubMenu)
-           continue;
-        else
-        {
-           hSubMenu = UserHMGetHandle(item->spSubMenu);
-           if (hSubMenu == hSubTarget)
-           {
-              return i;
-           }
-           else
-           {
-              HMENU hsubmenu = hSubMenu;
-              UINT pos = IntFindSubMenu( &hsubmenu, hSubTarget );
-              if (pos != NO_SELECTED_ITEM)
-              {
-                  *hMenu = hsubmenu;
-                  return pos;
-              }
-           }
-        }
-    }
-    return NO_SELECTED_ITEM;
+    pSubTarget = UserGetMenuObject(hSubTarget);
+
+    Pos = MENU_FindSubMenu(&menu, pSubTarget );
+
+    *hMenu = (menu ? UserHMGetHandle(menu) : NULL);
+
+    return Pos;
 }
 
 
@@ -1500,9 +4848,9 @@ UserMenuItemInfo(
       SetLastNtError(Status);
       return( FALSE);
    }
-   if (sizeof(MENUITEMINFOW) != Size
-         && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
-         && sizeof(ROSMENUITEMINFO) != Size)
+   if ( Size != sizeof(MENUITEMINFOW) && 
+        Size != FIELD_OFFSET(MENUITEMINFOW, hbmpItem) &&
+        Size != sizeof(ROSMENUITEMINFO) )
    {
       EngSetLastError(ERROR_INVALID_PARAMETER);
       return( FALSE);
@@ -1566,7 +4914,7 @@ UserMenuInfo(
       SetLastNtError(Status);
       return( FALSE);
    }
-   if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
+   if ( Size < sizeof(MENUINFO) || Size > sizeof(ROSMENUINFO) )
    {
       EngSetLastError(ERROR_INVALID_PARAMETER);
       return( FALSE);
@@ -1601,21 +4949,6 @@ UserMenuInfo(
    return( Res);
 }
 
-VOID FASTCALL
-MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect)
-{
-    if (menu->dwArrowsOn)
-    {
-        UINT arrow_bitmap_height;
-        //BITMAP bmp;
-        //GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
-        arrow_bitmap_height = gpsi->oembmi[65].cy; ///// Menu up arrow! OBM_UPARROW DFCS_MENUARROWUP
-        //arrow_bitmap_height = bmp.bmHeight;
-        rect->top += arrow_bitmap_height - menu->iTop;
-        rect->bottom += arrow_bitmap_height - menu->iTop;
-    }
-}
-
 BOOL FASTCALL
 IntGetMenuItemRect(
    PWND pWnd,
@@ -1625,14 +4958,9 @@ IntGetMenuItemRect(
 {
    LONG XMove, YMove;
    PITEM MenuItem;
+   UINT I = uItem;
 
-   if (!pWnd)
-   {
-      HWND hWnd = Menu->hWnd;
-      if (!(pWnd = UserGetWindowObject(hWnd))) return FALSE;
-   }
-
-   if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION)))
+   if ((MenuItem = MENU_FindItem (&Menu, &I, MF_BYPOSITION)))
    {
       Rect->left   = MenuItem->xItem;
       Rect->top    = MenuItem->yItem;
@@ -1645,6 +4973,12 @@ IntGetMenuItemRect(
       return FALSE;
    }
 
+   if (!pWnd)
+   {
+      HWND hWnd = Menu->hWnd;
+      if (!(pWnd = UserGetWindowObject(hWnd))) return FALSE;
+   }
+
    if (Menu->fFlags & MNF_POPUP)
    {
      XMove = pWnd->rcClient.left;
@@ -1685,7 +5019,7 @@ PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
    }
 
    SysMenu->fFlags |= MNF_SYSMENU;
-   SysMenu->hWnd = Window->head.h;
+   SysMenu->hWnd = UserHMGetHandle(Window);
 
    if (!Popup)
    {
@@ -1850,12 +5184,12 @@ IntSetMenu(
 
    if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
    {
-      ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd));
+      ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd));
       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
       return FALSE;
    }
 
-   *Changed = (Wnd->IDMenu != (UINT) Menu);
+   *Changed = (UlongToHandle(Wnd->IDMenu) != Menu);
    if (! *Changed)
    {
       return TRUE;
@@ -1863,8 +5197,8 @@ IntSetMenu(
 
    if (Wnd->IDMenu)
    {
-      OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
-      ASSERT(NULL == OldMenu || OldMenu->hWnd == Wnd->head.h);
+      OldMenu = IntGetMenuObject(UlongToHandle(Wnd->IDMenu));
+      ASSERT(NULL == OldMenu || OldMenu->hWnd == UserHMGetHandle(Wnd));
    }
    else
    {
@@ -1899,7 +5233,7 @@ IntSetMenu(
    Wnd->IDMenu = (UINT) Menu;
    if (NULL != NewMenu)
    {
-      NewMenu->hWnd = Wnd->head.h;
+      NewMenu->hWnd = UserHMGetHandle(Wnd);
       IntReleaseMenuObject(NewMenu);
    }
    if (NULL != OldMenu)
@@ -2217,6 +5551,36 @@ CLEANUP:
    END_CLEANUP;
 }
 
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserEndMenu(VOID)
+{
+   //PWND pWnd;
+   TRACE("Enter NtUserEndMenu\n");
+   UserEnterExclusive();
+ /*  if ( gptiCurrent->pMenuState &&
+        gptiCurrent->pMenuState->pGlobalPopupMenu )
+   {
+       pWnd = IntGetMSWND(gptiCurrent->pMenuState);
+       if (pWnd)
+       {
+          UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
+       }
+       else
+          gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
+   }*/
+   if (fInsideMenuLoop && top_popup)
+   {
+      fInsideMenuLoop = FALSE;
+      UserPostMessage( top_popup, WM_CANCELMODE, 0, 0);
+   }
+   UserLeave();
+   TRACE("Leave NtUserEndMenu\n");
+   return TRUE;
+}
+
 /*
  * @implemented
  */
@@ -2232,6 +5596,7 @@ NtUserGetMenuBarInfo(
    MENUBARINFO kmbi;
    BOOL Ret;
    PPOPUPMENU pPopupMenu;
+   USER_REFERENCE_ENTRY Ref;
    NTSTATUS Status = STATUS_SUCCESS;
    PMENU Menu = NULL;
    DECLARE_RETURN(BOOL);
@@ -2245,6 +5610,14 @@ NtUserGetMenuBarInfo(
         RETURN(FALSE);
    }
 
+   UserRefObjectCo(pWnd, &Ref);
+
+   RECTL_vSetEmptyRect(&kmbi.rcBar);
+   kmbi.hMenu = NULL;
+   kmbi.hwndMenu = NULL;
+   kmbi.fBarFocused = FALSE;
+   kmbi.fFocused = FALSE;
+
    switch (idObject)
    {
     case OBJID_CLIENT:
@@ -2258,14 +5631,24 @@ NtUserGetMenuBarInfo(
         }
         // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
         hMenu = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0);
+        pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
+        if (pPopupMenu && pPopupMenu->spmenu)
+        {
+           if (UserHMGetHandle(pPopupMenu->spmenu) != hMenu)
+           {
+              ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu->spmenu->head.h,hMenu);
+           }
+        }
         break;
     case OBJID_MENU:
+        if (pWnd->style & WS_CHILD) RETURN(FALSE);
         hMenu = UlongToHandle(pWnd->IDMenu);
+        TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu);
         break;
     case OBJID_SYSMENU:
         if (!(pWnd->style & WS_SYSMENU)) RETURN(FALSE);
         Menu = IntGetSystemMenu(pWnd, FALSE);
-        hMenu = Menu->head.h;
+        hMenu = UserHMGetHandle(Menu);
         break;
     default:
         RETURN(FALSE);
@@ -2276,6 +5659,7 @@ NtUserGetMenuBarInfo(
 
    _SEH2_TRY
    {
+       ProbeForRead(pmbi, sizeof(MENUBARINFO), 1);
        kmbi.cbSize = pmbi->cbSize;
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -2297,32 +5681,22 @@ NtUserGetMenuBarInfo(
    if ((idItem < 0) || ((ULONG)idItem > Menu->cItems))
        RETURN(FALSE);
 
-   RECTL_vSetEmptyRect(&kmbi.rcBar);
-
    if (idItem == 0)
    {
       Ret = IntGetMenuItemRect(pWnd, Menu, 0, &kmbi.rcBar);
       kmbi.rcBar.right = kmbi.rcBar.left + Menu->cxMenu;
       kmbi.rcBar.bottom = kmbi.rcBar.top + Menu->cyMenu;
-      TRACE("idItem 0 %d\n",Ret);
+      TRACE("idItem 0 %d\n",Ret);
    }
    else
    {
       Ret = IntGetMenuItemRect(pWnd, Menu, idItem-1, &kmbi.rcBar);
-      TRACE("idItem X %d\n", Ret);
+      TRACE("idItem b %d %d\n", idItem-1, Ret);
    }
 
    kmbi.hMenu = hMenu;
-   kmbi.hwndMenu = NULL;
-   kmbi.fBarFocused = FALSE;
-   kmbi.fFocused = FALSE;
-
-   pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
-   if (pPopupMenu)
-   {
-      //kmbi.fBarFocused = pPopupMenu->spmenu == Menu;
-   }
-
+   kmbi.fBarFocused = top_popup_hmenu == hMenu;
+   TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu, hMenu);
    if (idItem)
    {
        kmbi.fFocused = Menu->iItem == idItem-1;
@@ -2331,13 +5705,14 @@ NtUserGetMenuBarInfo(
           kmbi.hwndMenu = Menu->rgItems[idItem - 1].spSubMenu->hWnd;
        }
    }
-/*   else
+   else
    {
        kmbi.fFocused = kmbi.fBarFocused;
-   }*/
+   }
 
    _SEH2_TRY
    {
+      ProbeForWrite(pmbi, sizeof(MENUBARINFO), 1);
       RtlCopyMemory(pmbi, &kmbi, sizeof(MENUBARINFO));
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -2355,6 +5730,7 @@ NtUserGetMenuBarInfo(
    RETURN(TRUE);
 
 CLEANUP:
+   if (pWnd) UserDerefObjectCo(pWnd);
    TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
@@ -2515,6 +5891,63 @@ CLEANUP:
    END_CLEANUP;
 }
 
+/*
+ * @implemented
+ */
+DWORD
+APIENTRY
+NtUserDrawMenuBarTemp(
+   HWND hWnd,
+   HDC hDC,
+   PRECT pRect,
+   HMENU hMenu,
+   HFONT hFont)
+{
+   PMENU Menu;
+   PWND Window;
+   RECT Rect;
+   NTSTATUS Status = STATUS_SUCCESS;
+   DECLARE_RETURN(DWORD);
+
+   ERR("Enter NtUserDrawMenuBarTemp\n");
+   UserEnterExclusive();
+
+   if(!(Window = UserGetWindowObject(hWnd)))
+   {
+      EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+      RETURN(0);
+   }
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      EngSetLastError(ERROR_INVALID_MENU_HANDLE);
+      RETURN(0);
+   }
+
+   _SEH2_TRY
+   {
+      ProbeForRead(pRect, sizeof(RECT), sizeof(ULONG));
+      RtlCopyMemory(&Rect, pRect, sizeof(RECT));
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      Status = _SEH2_GetExceptionCode();
+   }
+   _SEH2_END;
+
+   if (Status != STATUS_SUCCESS)
+   {
+      SetLastNtError(Status);
+      RETURN(0);
+   }
+
+   RETURN( IntDrawMenuBarTemp(Window, hDC, &Rect, Menu, hFont));
+
+CLEANUP:
+   ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
 
 /*
  * @implemented
@@ -2552,11 +5985,14 @@ NtUserMenuItemFromPoint(
    for (i = 0; i < Menu->cItems; i++, mi++)
    {
       RECTL Rect;
+
       Rect.left   = mi->xItem;
       Rect.top    = mi->yItem;
-      Rect.right  = mi->cxItem; // Do this for now......
+      Rect.right  = mi->cxItem;
       Rect.bottom = mi->cyItem;
-      //MENU_AdjustMenuItemRect(Menu, &Rect); Need gpsi OBMI via callback!
+
+      MENU_AdjustMenuItemRect(Menu, &Rect);
+
       if (RECTL_bPointInRect(&Rect, X, Y))
       {
          break;
@@ -2622,7 +6058,7 @@ NtUserSetMenu(
       RETURN( FALSE);
    }
 
-   if (! IntSetMenu(Window, Menu, &Changed))
+   if (!IntSetMenu(Window, Menu, &Changed))
    {
       RETURN( FALSE);
    }
@@ -2807,4 +6243,61 @@ CLEANUP:
    END_CLEANUP;
 }
 
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserTrackPopupMenuEx(
+   HMENU hMenu,
+   UINT fuFlags,
+   int x,
+   int y,
+   HWND hWnd,
+   LPTPMPARAMS lptpm)
+{
+   PMENU menu;
+   PWND pWnd;
+   TPMPARAMS tpm;
+   BOOL Ret = FALSE;
+   USER_REFERENCE_ENTRY Ref;
+
+   TRACE("Enter NtUserTrackPopupMenuEx\n");
+   UserEnterExclusive();
+   /* Parameter check */
+   if (!(menu = UserGetMenuObject( hMenu )))
+   {
+      ERR("TPME : Invalid Menu handle.\n");
+      EngSetLastError( ERROR_INVALID_MENU_HANDLE );
+      goto Exit;
+   }
+
+   if (!(pWnd = UserGetWindowObject(hWnd)))
+   {
+      ERR("TPME : Invalid Window handle.\n");
+      goto Exit;
+   }
+
+   if (lptpm)
+   {
+      _SEH2_TRY
+      {
+         ProbeForRead(lptpm, sizeof(TPMPARAMS), sizeof(ULONG));
+         tpm = *lptpm;
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      { 
+         _SEH2_YIELD(goto Exit);
+      }
+      _SEH2_END
+   }
+   UserRefObjectCo(pWnd, &Ref);
+   Ret = IntTrackPopupMenuEx(menu, fuFlags, x, y, pWnd, lptpm ? &tpm : NULL);
+   UserDerefObjectCo(pWnd);
+
+Exit:
+   TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret);
+   UserLeave();
+   return Ret;
+}
+
 /* EOF */
index ca01889..77eff65 100644 (file)
@@ -66,6 +66,62 @@ typedef struct _SETMENUITEMRECT
   RECTL rcRect;
 } SETMENUITEMRECT, *PSETMENUITEMRECT;
 
+
+//
+// Legacy ReactOS Menu transfer structures.
+//
+typedef struct tagROSMENUINFO
+{
+    /* ----------- MENUINFO ----------- */
+    DWORD cbSize;
+    DWORD fMask;
+    DWORD dwStyle;
+    UINT cyMax;
+    HBRUSH  hbrBack;
+    DWORD dwContextHelpID;
+    ULONG_PTR dwMenuData;
+    /* ----------- Extra ----------- */
+    ULONG fFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
+    UINT iItem; /* Currently focused item */
+    UINT cItems; /* Number of items in the menu */
+    WORD cxMenu; /* Width of the whole menu */
+    WORD cyMenu; /* Height of the whole menu */
+    ULONG cxTextAlign;
+    PWND spwndNotify; /* window receiving the messages for ownerdraw */
+    INT iTop;
+    INT iMaxTop;
+    DWORD dwArrowsOn:2;
+
+    HMENU Self; /* Handle of this menu */
+    HWND Wnd; /* Window containing the menu */
+    BOOL TimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
+} ROSMENUINFO, *PROSMENUINFO;
+
+typedef struct tagROSMENUITEMINFO
+{
+    /* ----------- MENUITEMINFOW ----------- */
+    UINT cbSize;
+    UINT fMask;
+    UINT fType;
+    UINT fState;
+    UINT wID;
+    HMENU hSubMenu;
+    HBITMAP hbmpChecked;
+    HBITMAP hbmpUnchecked;
+    DWORD dwItemData;
+    LPWSTR dwTypeData;
+    UINT cch;
+    HBITMAP hbmpItem;
+    /* ----------- Extra ----------- */
+    RECT Rect; /* Item area (relative to menu window) */
+    UINT dxTab; /* X position of text after Tab */
+    LPWSTR lpstr; /* Copy of the text pointer in MenuItem->Text */
+    SIZE maxBmpSize; /* Maximum size of the bitmap items in MIIM_BITMAP state */
+} ROSMENUITEMINFO, *PROSMENUITEMINFO;
+//
+//
+//
+
 PMENU FASTCALL
 IntGetMenuObject(HMENU hMenu);
 
@@ -101,3 +157,14 @@ BOOL FASTCALL IntRemoveMenuItem(PMENU Menu, UINT uPosition, UINT uFlags, BOOL bR
 PITEM FASTCALL MENU_FindItem( PMENU *pmenu, UINT *nPos, UINT wFlags );
 BOOL FASTCALL IntMenuItemInfo(PMENU Menu, UINT Item, BOOL ByPosition, PROSMENUITEMINFO UnsafeItemInfo, BOOL SetOrGet, PUNICODE_STRING lpstr);
 BOOL FASTCALL IntSetMenu(PWND Wnd,HMENU Menu,BOOL *Changed);
+UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, PWND pWnd, BOOL suppress_draw );
+BOOL MenuInit(VOID);
+VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar);
+VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt);
+BOOL WINAPI PopupMenuWndProc(PWND Wnd,UINT Message,WPARAM wParam,LPARAM lParam,LRESULT *lResult);
+BOOL FASTCALL IntSetMenuItemInfo(PMENU, PITEM, PROSMENUITEMINFO, PUNICODE_STRING);
+PWND MENU_IsMenuActive(VOID);
+void MENU_EndMenu( PWND pwnd );
+void FASTCALL MENU_InitSysMenuPopup(PMENU menu, DWORD style, DWORD clsStyle, LONG HitTest );
+INT FASTCALL IntMenuItemFromPoint(PWND pWnd, HMENU hMenu, POINT ptScreen);
+BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int y, PWND pWnd, LPTPMPARAMS lpTpm);
index 6b21310..262ca9d 100644 (file)
@@ -136,6 +136,10 @@ static MSGMEMORY g_MsgMemory[] =
     { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
     { WM_SIZING, sizeof(RECT), MMS_FLAG_READWRITE },
     { WM_MOVING, sizeof(RECT), MMS_FLAG_READWRITE },
+    { WM_MEASUREITEM, sizeof(MEASUREITEMSTRUCT), MMS_FLAG_READWRITE },
+    { WM_DRAWITEM, sizeof(DRAWITEMSTRUCT), MMS_FLAG_READWRITE },
+    { WM_HELP, sizeof(HELPINFO), MMS_FLAG_READWRITE },
+    { WM_NEXTMENU, sizeof(MDINEXTMENU), MMS_FLAG_READWRITE },
 };
 
 static PMSGMEMORY FASTCALL
@@ -745,7 +749,13 @@ IntDispatchMessage(PMSG pMsg)
                                                  pMsg->message,
                                                  pMsg->wParam,
                                                  pMsg->lParam,
-                                                 &retval);
+                                                &retval);
+          case FNID_MENU:
+            DoCallBack = !PopupMenuWndProc( Window,
+                                            pMsg->message,
+                                            pMsg->wParam,
+                                            pMsg->lParam,
+                                           &retval);
             break;
        }
     }
@@ -949,7 +959,7 @@ co_IntPeekMessage( PMSG Msg,
     return TRUE;
 }
 
-static BOOL FASTCALL
+BOOL FASTCALL
 co_IntWaitMessage( PWND Window,
                    UINT MsgFilterMin,
                    UINT MsgFilterMax )
@@ -1353,6 +1363,9 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
               case FNID_MESSAGEWND:
                 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
                 break;
+              case FNID_MENU:
+                DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result);
+                break;
            }
            if (!DoCallBack)
            {
@@ -1644,6 +1657,9 @@ co_IntSendMessageWithCallBack( HWND hWnd,
               case FNID_MESSAGEWND:
                 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
                 break;
+              case FNID_MENU:
+                DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result);
+                break;
            }
         }
 
@@ -2333,13 +2349,21 @@ NtUserMessageCall( HWND hWnd,
            }
            break;
         }
-
+   case FNID_MENU:
+       {
+          Window = UserGetWindowObject(hWnd);
+          if (Window)
+          {
+              Ret = PopupMenuWndProc( Window, Msg, wParam, lParam, &lResult);
+          }
+          break;
+       }
    case FNID_MESSAGEWND:
        {
            Window = UserGetWindowObject(hWnd);
            if (Window)
            {
-                Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam,&lResult);
+                Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam, &lResult);
            }
            break;
        }
@@ -2832,6 +2856,7 @@ NtUserMessageCall( HWND hWnd,
     case FNID_CALLWNDPROCRET:
     case FNID_SCROLLBAR:
     case FNID_DESKTOP:
+    case FNID_MENU:
         if (ResultInfo)
         {
             _SEH2_TRY
index ba7db31..87baf1d 100644 (file)
@@ -397,6 +397,28 @@ NtUserGetGUIThreadInfo(
    CaretInfo = MsgQueue->CaretInfo;
 
    SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
+/*
+   if (W32Thread->pMenuState->pGlobalPopupMenu)
+   {
+       SafeGui.flags |= GUI_INMENUMODE;
+
+       if (W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify)
+          SafeGui.hwndMenuOwner = UserHMGetHandle(W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify);
+
+       if (W32Thread->pMenuState->pGlobalPopupMenu->fHasMenuBar)
+       {
+          if (W32Thread->pMenuState->pGlobalPopupMenu->fIsSysMenu)
+          {
+             SafeGui.flags |= GUI_SYSTEMMENUMODE;
+          }
+       }
+       else
+       {
+          SafeGui.flags |= GUI_POPUPMENUMODE;
+       }
+   }
+ */
+   SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
 
    if (MsgQueue->MenuOwner)
       SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
@@ -409,7 +431,6 @@ NtUserGetGUIThreadInfo(
    SafeGui.hwndActive = MsgQueue->spwndActive ? UserHMGetHandle(MsgQueue->spwndActive) : 0;
    SafeGui.hwndFocus = MsgQueue->spwndFocus ? UserHMGetHandle(MsgQueue->spwndFocus) : 0;
    SafeGui.hwndCapture = MsgQueue->spwndCapture ? UserHMGetHandle(MsgQueue->spwndCapture) : 0;
-   SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
    SafeGui.hwndMoveSize = MsgQueue->MoveSize;
    SafeGui.hwndCaret = CaretInfo->hWnd;
 
index 911c32a..3a7fe54 100644 (file)
@@ -2005,8 +2005,28 @@ NTSTATUS FASTCALL
 co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
                          UINT MsgFilterMin, UINT MsgFilterMax)
 {
-   NTSTATUS ret;
+   NTSTATUS ret = STATUS_SUCCESS;
+
+   // Post mouse moves before waiting for messages.
+   if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
+   {
+      IntCoalesceMouseMove(pti);
+   }
+
+   if ( pti->nCntsQBits[QSRosMouseButton] != 0 ||
+        pti->nCntsQBits[QSRosMouseMove]   != 0 ||
+        pti->nCntsQBits[QSRosKey]         != 0 ||
+        pti->nCntsQBits[QSRosSendMessage] != 0 ||
+        pti->nCntsQBits[QSRosPostMessage] != 0 )
+   {
+      TRACE("No time to wait!\n");
+      return ret;
+   }
+
    UserLeaveCo();
+
+   ZwYieldExecution(); // Let someone else run!
+
    ret = KeWaitForSingleObject( pti->pEventQueueServer,
                                 UserRequest,
                                 UserMode,
index c552acc..f7b92b4 100644 (file)
@@ -274,5 +274,9 @@ UserPostThreadMessage( PTHREADINFO pti,
                        UINT Msg,
                        WPARAM wParam,
                        LPARAM lParam );
+BOOL FASTCALL
+co_IntWaitMessage( PWND Window,
+                   UINT MsgFilterMin,
+                   UINT MsgFilterMax );
 
 /* EOF */
index 6a10bab..dd2dafd 100644 (file)
@@ -31,6 +31,12 @@ DBG_DEFAULT_CHANNEL(UserDefwnd);
 #define ON_BOTTOM_BORDER(hit) \
  (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
 
+#define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
+            ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE))  || \
+             ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
+             (WindowRect.right - WindowRect.left == ParentClientRect.right) && \
+             (WindowRect.bottom - WindowRect.top == ParentClientRect.bottom)))
+
 
 VOID FASTCALL
 UserDrawWindowFrame(HDC hdc,
@@ -109,6 +115,32 @@ NC_GetInsideRect(PWND Wnd, RECT *rect)
     }
 }
 
+/***********************************************************************
+ *           NC_GetSysPopupPos
+ */
+void FASTCALL
+NC_GetSysPopupPos(PWND Wnd, RECT *Rect)
+{
+  RECT WindowRect;
+
+  if ((Wnd->style & WS_MINIMIZE) != 0)
+  {
+      IntGetWindowRect(Wnd, Rect);
+  }
+  else
+    {
+      NC_GetInsideRect(Wnd, Rect);
+      IntGetWindowRect(Wnd, &WindowRect);
+      RECTL_vOffsetRect(Rect, WindowRect.left, WindowRect.top);
+      if (Wnd->style & WS_CHILD)
+      {
+          IntClientToScreen(IntGetParent(Wnd), (POINT *) Rect);
+      }
+      Rect->right = Rect->left + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+      Rect->bottom = Rect->top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+    }
+}
+
 LONG FASTCALL
 DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint)
 {
@@ -598,6 +630,1073 @@ PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd )
    return pIcon;
 }
 
+BOOL
+UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down)
+{
+   PCURICON_OBJECT WindowIcon;
+   BOOL Ret = FALSE;
+
+   if ((WindowIcon = NC_IconForWindow(pWnd)))
+   {
+      UserReferenceObject(WindowIcon);
+
+      Ret = UserDrawIconEx( hDC,
+                            Rect->left + 2,
+                            Rect->top + 2,
+                            WindowIcon,
+                            UserGetSystemMetrics(SM_CXSMICON),
+                            UserGetSystemMetrics(SM_CYSMICON),
+                            0, NULL, DI_NORMAL);
+
+      UserDereferenceObject(WindowIcon);
+   }
+   return Ret;
+}
+
+void
+UserGetInsideRectNC(PWND Wnd, RECT *rect)
+{
+    ULONG Style;
+    ULONG ExStyle;
+
+    Style = Wnd->style;
+    ExStyle = Wnd->ExStyle;
+
+    rect->top    = rect->left = 0;
+    rect->right  = Wnd->rcWindow.right - Wnd->rcWindow.left;
+    rect->bottom = Wnd->rcWindow.bottom - Wnd->rcWindow.top;
+
+    if (Style & WS_ICONIC)
+    {
+        return;
+    }
+
+    /* Remove frame from rectangle */
+    if (UserHasThickFrameStyle(Style, ExStyle ))
+    {
+        RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME));
+    }
+    else
+    {
+        if (UserHasDlgFrameStyle(Style, ExStyle ))
+        {
+            RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
+            /* FIXME: this isn't in NC_AdjustRect? why not? */
+            if (ExStyle & WS_EX_DLGMODALFRAME)
+                   RECTL_vInflateRect( rect, -1, 0 );
+        }
+        else
+        {
+            if (UserHasThinFrameStyle(Style, ExStyle))
+            {
+                RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
+            }
+        }
+    }
+    /* We have additional border information if the window
+     * is a child (but not an MDI child) */
+    if ((Style & WS_CHILD) && !(ExStyle & WS_EX_MDICHILD))
+    {
+       if (ExStyle & WS_EX_CLIENTEDGE)
+          RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
+       if (ExStyle & WS_EX_STATICEDGE)
+          RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
+    }
+}
+
+BOOL
+IntIsScrollBarVisible(PWND pWnd, INT hBar)
+{
+  SCROLLBARINFO sbi;
+  sbi.cbSize = sizeof(SCROLLBARINFO);
+
+  if(!co_IntGetScrollBarInfo(pWnd, hBar, &sbi))
+    return FALSE;
+
+  return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
+}
+
+BOOL
+UserHasMenu(PWND pWnd, ULONG Style)
+{
+   return (!(Style & WS_CHILD) && UlongToHandle(pWnd->IDMenu) != 0);
+}
+
+/*
+ * FIXME:
+ * - Cache bitmaps, then just bitblt instead of calling DFC() (and
+ *   wasting precious CPU cycles) every time
+ * - Center the buttons verticaly in the rect
+ */
+VOID
+UserDrawCaptionButton(PWND pWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type)
+{
+   RECT TempRect;
+
+   if (!(Style & WS_SYSMENU))
+   {
+      return;
+   }
+
+   TempRect = *Rect;
+
+   switch (Type)
+   {
+      case DFCS_CAPTIONMIN:
+      {
+         if (ExStyle & WS_EX_TOOLWINDOW)
+            return; /* ToolWindows don't have min/max buttons */
+
+         if (Style & WS_SYSMENU)
+             TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+
+         if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
+             TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) - 2;
+
+         TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
+         TempRect.top += 2;
+         TempRect.right -= 1;
+
+         DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
+                          ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) |
+                          (bDown ? DFCS_PUSHED : 0) |
+                          ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE));
+         break;
+      }
+      case DFCS_CAPTIONMAX:
+      {
+         if (ExStyle & WS_EX_TOOLWINDOW)
+             return; /* ToolWindows don't have min/max buttons */
+
+         if (Style & WS_SYSMENU)
+             TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+
+         TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
+         TempRect.top += 2;
+         TempRect.right -= 1;
+
+         DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
+                          ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) |
+                          (bDown ? DFCS_PUSHED : 0) |
+                          ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE));
+         break;
+      }
+      case DFCS_CAPTIONCLOSE:
+      {
+          PMENU pSysMenu = IntGetSystemMenu(pWnd, FALSE);
+          UINT MenuState = IntGetMenuState(UserHMGetHandle(pSysMenu), SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
+
+         /* FIXME: A tool window has a smaller Close button */
+
+         if (ExStyle & WS_EX_TOOLWINDOW)
+         {
+            TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSMSIZE);
+            TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMSIZE) - 2;
+         }
+         else
+         {
+            TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE);
+            TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
+         }
+         TempRect.top += 2;
+         TempRect.right -= 2;
+
+         DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
+                          (DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) |
+                          ((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(pWnd->pcls->style & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE)));
+         break;
+      }
+   }
+}
+
+VOID
+UserDrawCaptionButtonWnd(PWND pWnd, HDC hDC, BOOL bDown, ULONG Type)
+{
+   RECT WindowRect;
+   SIZE WindowBorder;
+
+   IntGetWindowRect(pWnd, &WindowRect);
+
+   WindowRect.right -= WindowRect.left;
+   WindowRect.bottom -= WindowRect.top;
+   WindowRect.left = WindowRect.top = 0;
+
+   UserGetWindowBorders(pWnd->style, pWnd->ExStyle, &WindowBorder, FALSE);
+
+   RECTL_vInflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy);
+
+   UserDrawCaptionButton(pWnd, &WindowRect, pWnd->style, pWnd->ExStyle, hDC, bDown, Type);
+}
+
+VOID
+NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle)
+{
+   /* Firstly the "thick" frame */
+   if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
+   {
+      LONG Width =
+         (UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME)) *
+         UserGetSystemMetrics(SM_CXBORDER);
+
+      LONG Height =
+         (UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME)) *
+         UserGetSystemMetrics(SM_CYBORDER);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
+
+      /* Draw frame */
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+
+      RECTL_vInflateRect(CurrentRect, -Width, -Height);
+   }
+
+   /* Now the other bit of the frame */
+   if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
+   {
+      DWORD Width = UserGetSystemMetrics(SM_CXBORDER);
+      DWORD Height = UserGetSystemMetrics(SM_CYBORDER);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(
+         (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
+         (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
+         (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
+         COLOR_WINDOWFRAME));
+
+      /* Draw frame */
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
+
+      RECTL_vInflateRect(CurrentRect, -Width, -Height);
+   }
+}
+
+VOID UserDrawCaptionBar(
+   PWND pWnd,
+   HDC hDC,
+   INT Flags)
+{
+   DWORD Style, ExStyle;
+   RECT WindowRect, CurrentRect, TempRect;
+   HPEN PreviousPen;
+   BOOL Gradient = FALSE;
+   PCURICON_OBJECT pIcon = NULL;
+
+   if (!(Flags & DC_NOVISIBLE) && !IntIsWindowVisible(pWnd)) return;
+
+   TRACE("UserDrawCaptionBar: pWnd %p, hDc %p, Flags 0x%x.\n", pWnd, hDC, Flags);
+
+   Style = pWnd->style;
+   ExStyle = pWnd->ExStyle;
+
+   IntGetWindowRect(pWnd, &WindowRect);
+
+   CurrentRect.top = CurrentRect.left = 0;
+   CurrentRect.right = WindowRect.right - WindowRect.left;
+   CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
+
+   /* Draw outer edge */
+   if (UserHasWindowEdge(Style, ExStyle))
+   {
+      DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
+   }
+   else if (ExStyle & WS_EX_STATICEDGE)
+   {
+#if 0
+      DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
+#else
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      RECTL_vInflateRect(&CurrentRect, -1, -1);
+#endif
+   }
+
+   if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, (Flags & DC_ACTIVE), Style, ExStyle);
+
+   /* Draw caption */
+   if ((Style & WS_CAPTION) == WS_CAPTION)
+   {
+      TempRect = CurrentRect;
+
+      if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
+      {
+         Flags |= DC_GRADIENT;
+      }
+
+      if (ExStyle & WS_EX_TOOLWINDOW)
+      {
+         Flags |= DC_SMALLCAP;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
+      }
+      else
+      {
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
+      }
+
+      if (!(Flags & DC_ICON)               &&
+           (Style & WS_SYSMENU)            &&
+          !(Flags & DC_SMALLCAP)           &&
+          !(ExStyle & WS_EX_DLGMODALFRAME) && 
+          !(ExStyle & WS_EX_TOOLWINDOW) )
+      {
+         pIcon = NC_IconForWindow(pWnd); // Force redraw of caption with icon if DC_ICON not flaged....
+      }
+      UserDrawCaption(pWnd, hDC, &TempRect, NULL, pIcon ? UserHMGetHandle(pIcon) : NULL, NULL, Flags);
+
+      /* Draw buttons */
+      if (Style & WS_SYSMENU)
+      {
+         UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
+         if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
+         {
+            UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
+            UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
+         }
+      }
+
+      if (!(Style & WS_MINIMIZE))
+      {
+         /* Line under caption */
+         PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
+
+         IntSetDCPenColor( hDC, IntGetSysColor(((ExStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
+                                             COLOR_WINDOWFRAME : COLOR_3DFACE));
+
+         GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
+
+         NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
+
+         NtGdiSelectPen(hDC, PreviousPen);
+      }
+   }
+
+   if (!(Style & WS_MINIMIZE))
+   {
+      if (ExStyle & WS_EX_CLIENTEDGE)
+      {
+          DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+      }
+   }
+}
+
+// Note from Wine:
+/* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
+   the call to GetDCEx implying that it is allowed not to use it either.
+   However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
+   will cause clipRgn to be deleted after ReleaseDC().
+   Now, how is the "system" supposed to tell what happened?
+ */
+/*
+ * FIXME:
+ * - Drawing of WS_BORDER after scrollbars
+ * - Correct drawing of size-box
+ */
+LRESULT
+NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags)
+{
+   DWORD Style, ExStyle;
+   PWND Parent;
+   RECT WindowRect, CurrentRect, TempRect;
+   BOOL Active = FALSE;
+   PCURICON_OBJECT pIcon = NULL;
+
+   if (!IntIsWindowVisible(pWnd) ||
+       (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) ||
+        IntEqualRect(&pWnd->rcWindow, &pWnd->rcClient) )
+      return 0;
+
+   Style = pWnd->style;
+
+   TRACE("DefWndNCPaint: pWnd %p, hDc %p, Active %s.\n", pWnd, hDC, Flags & DC_ACTIVE ? "TRUE" : "FALSE");
+
+   Parent = IntGetParent(pWnd);
+   ExStyle = pWnd->ExStyle;
+
+   if (Flags == -1) // NC paint mode.
+   {
+      if (ExStyle & WS_EX_MDICHILD)
+      {
+         Active = IntIsChildWindow(gpqForeground->spwndActive, pWnd);
+
+         if (Active)
+            Active = (UserHMGetHandle(pWnd) == (HWND)co_IntSendMessage(UserHMGetHandle(Parent), WM_MDIGETACTIVE, 0, 0));
+      }
+      else
+      {
+         Active = (gpqForeground == pWnd->head.pti->MessageQueue);
+      }
+      Flags = DC_NC;
+   }
+
+   IntGetWindowRect(pWnd, &WindowRect);
+
+   CurrentRect.top = CurrentRect.left = 0;
+   CurrentRect.right = WindowRect.right - WindowRect.left;
+   CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
+
+   /* Draw outer edge */
+   if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle))
+   {
+      DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
+   }
+   else if (pWnd->ExStyle & WS_EX_STATICEDGE)
+   {
+#if 0
+      DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
+#else
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
+      NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
+      NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
+
+      RECTL_vInflateRect(&CurrentRect, -1, -1);
+#endif
+   }
+
+   if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, Active ? Active : (Flags & DC_ACTIVE), Style, ExStyle);
+
+   /* Draw caption */
+   if ((Style & WS_CAPTION) == WS_CAPTION)
+   {
+      HPEN PreviousPen;
+      BOOL Gradient = FALSE;
+
+      if (Flags & DC_REDRAWHUNGWND)
+      {
+         Flags &= ~DC_REDRAWHUNGWND;
+         Flags |= DC_NOSENDMSG;
+      }
+
+      if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
+      {
+         Flags |= DC_GRADIENT;
+      }
+
+      if (Active)
+      {
+         if (!(pWnd->state & WNDS_ACTIVEFRAME))
+         {
+            ERR("Wnd is active and not set active!\n");
+         }
+         Flags |= DC_ACTIVE;
+      }
+
+      TempRect = CurrentRect;
+
+      if (ExStyle & WS_EX_TOOLWINDOW)
+      {
+         Flags |= DC_SMALLCAP;
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
+      }
+      else
+      {
+         TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
+         CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
+      }
+
+      if (!(Flags & DC_ICON)               &&
+           (Style & WS_SYSMENU)            &&
+          !(Flags & DC_SMALLCAP)           &&
+          !(ExStyle & WS_EX_DLGMODALFRAME) && 
+          !(ExStyle & WS_EX_TOOLWINDOW) )
+      {
+         pIcon = NC_IconForWindow(pWnd); // Force redraw of caption with icon if DC_ICON not flaged....
+      }
+      UserDrawCaption(pWnd, hDC, &TempRect, NULL, pIcon ? UserHMGetHandle(pIcon) : NULL, NULL, Flags);
+
+      /* Draw buttons */
+      if (Style & WS_SYSMENU)
+      {
+         UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
+         if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
+         {
+            UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
+            UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
+         }
+      }
+      if (!(Style & WS_MINIMIZE))
+      {
+        /* Line under caption */
+         PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
+
+         IntSetDCPenColor( hDC, IntGetSysColor(
+                         ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
+                          COLOR_WINDOWFRAME : COLOR_3DFACE));
+
+         GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
+
+         NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
+
+         NtGdiSelectPen(hDC, PreviousPen);
+      }
+   }
+
+   if (!(Style & WS_MINIMIZE))
+   {
+     PMENU menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
+     /* Draw menu bar */
+     if (menu && !(Style & WS_CHILD))
+     {
+         TempRect = CurrentRect;
+         TempRect.bottom = TempRect.top + menu->cyMenu;
+         CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE);
+     }
+
+     if (ExStyle & WS_EX_CLIENTEDGE)
+     {
+         DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+     }
+
+     /* Draw the scrollbars */
+     if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
+         IntIsScrollBarVisible(pWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
+     {
+        RECT ParentClientRect;
+
+        TempRect = CurrentRect;
+
+        if (ExStyle & WS_EX_LEFTSCROLLBAR)
+           TempRect.right = TempRect.left + UserGetSystemMetrics(SM_CXVSCROLL);
+        else
+           TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXVSCROLL);
+
+        TempRect.top = TempRect.bottom - UserGetSystemMetrics(SM_CYHSCROLL);
+
+        FillRect(hDC, &TempRect, IntGetSysColorBrush(COLOR_BTNFACE));
+
+        if (Parent)
+           IntGetClientRect(Parent, &ParentClientRect);
+
+        if (HASSIZEGRIP(Style, ExStyle, Parent->style, WindowRect, ParentClientRect))
+        {
+           DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
+        }
+
+        IntDrawScrollBar(pWnd, hDC, SB_VERT);
+        IntDrawScrollBar(pWnd, hDC, SB_HORZ);
+     }
+     else
+     {
+        if (Style & WS_VSCROLL && IntIsScrollBarVisible(pWnd, OBJID_VSCROLL))
+        {
+           IntDrawScrollBar(pWnd, hDC, SB_VERT);
+        }
+        else if (Style & WS_HSCROLL && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
+        {
+           IntDrawScrollBar(pWnd, hDC, SB_HORZ);
+        }
+     }
+   }
+   return 0; // For WM_NCPAINT message, return 0.
+}
+
+LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect )
+{
+   LRESULT Result = 0;
+   SIZE WindowBorders;
+   RECT OrigRect;
+   DWORD Style = Wnd->style;
+
+   if (Rect == NULL)
+   {
+      return Result;
+   }
+   OrigRect = *Rect;
+
+   Wnd->state &= ~WNDS_HASCAPTION;
+
+   if (wparam)
+   {
+      if (Wnd->pcls->style & CS_VREDRAW)
+      {
+         Result |= WVR_VREDRAW;
+      }
+      if (Wnd->pcls->style & CS_HREDRAW)
+      {
+         Result |= WVR_HREDRAW;
+      }
+      Result |= WVR_VALIDRECTS;
+   }
+
+   if (!(Wnd->style & WS_MINIMIZE))
+   {
+      if (UserHasWindowEdge(Wnd->style, Wnd->ExStyle))
+      {
+         UserGetWindowBorders(Wnd->style, Wnd->ExStyle, &WindowBorders, FALSE);
+         RECTL_vInflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
+      }
+      else if ((Wnd->ExStyle & WS_EX_STATICEDGE) || (Wnd->style & WS_BORDER))
+      {
+         RECTL_vInflateRect(Rect, -1, -1);
+      }
+
+      if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
+      {
+         Wnd->state |= WNDS_HASCAPTION;
+
+         if (Wnd->ExStyle & WS_EX_TOOLWINDOW)
+            Rect->top += UserGetSystemMetrics(SM_CYSMCAPTION);
+         else
+            Rect->top += UserGetSystemMetrics(SM_CYCAPTION);
+      }
+
+      if (Wnd->IDMenu && ((Wnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD))
+      {
+         HDC hDC = UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
+
+         Wnd->state |= WNDS_HASMENU;
+
+         if (hDC)
+         {
+           RECT CliRect = *Rect;
+           CliRect.bottom -= OrigRect.top;
+           CliRect.right -= OrigRect.left;
+           CliRect.left -= OrigRect.left;
+           CliRect.top -= OrigRect.top;
+           Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE);
+           UserReleaseDC(Wnd, hDC, FALSE);
+         }
+      }
+
+      if (Wnd->ExStyle & WS_EX_CLIENTEDGE)
+      {
+         RECTL_vInflateRect(Rect, -2 * UserGetSystemMetrics(SM_CXBORDER), -2 * UserGetSystemMetrics(SM_CYBORDER));
+      }
+
+      if (Wnd->style & (WS_VSCROLL | WS_HSCROLL))
+      {
+        SCROLLBARINFO sbi;
+        SETSCROLLBARINFO ssbi;
+
+        sbi.cbSize = sizeof(SCROLLBARINFO);
+        if ((Style & WS_VSCROLL) && co_IntGetScrollBarInfo(Wnd, OBJID_VSCROLL, &sbi))
+        {
+          int i;
+          LONG sx = Rect->right;
+
+          Wnd->state |= WNDS_HASVERTICALSCROOLLBAR;
+
+          sx -= UserGetSystemMetrics(SM_CXVSCROLL);
+
+          for (i = 0; i <= CCHILDREN_SCROLLBAR; i++)
+              ssbi.rgstate[i] = sbi.rgstate[i];
+
+          if (sx <= Rect->left)
+             ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
+          else
+             ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
+
+          co_IntSetScrollBarInfo(Wnd, OBJID_VSCROLL, &ssbi);
+
+          if (ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
+             Style &= ~WS_VSCROLL;
+        }
+        else
+          Style &= ~WS_VSCROLL;
+
+        if ((Style & WS_HSCROLL) && co_IntGetScrollBarInfo(Wnd, OBJID_HSCROLL, &sbi))
+        {
+          int i;
+          LONG sy = Rect->bottom;
+
+          Wnd->state |= WNDS_HASHORIZONTALSCROLLBAR;
+
+          sy -= UserGetSystemMetrics(SM_CYHSCROLL);
+
+          for (i = 0; i <= CCHILDREN_SCROLLBAR; i++)
+              ssbi.rgstate[i] = sbi.rgstate[i];
+
+          if (sy <= Rect->top)
+             ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
+          else
+             ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
+
+          co_IntSetScrollBarInfo(Wnd, OBJID_HSCROLL, &ssbi);
+
+          if (ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
+             Style &= ~WS_HSCROLL;
+        }
+        else
+          Style &= ~WS_HSCROLL;
+      }
+
+      if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL))
+      {
+         if ((Wnd->ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+            Rect->left += UserGetSystemMetrics(SM_CXVSCROLL);
+         else
+            Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
+
+         Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
+      }
+      else
+      {
+         if (Style & WS_VSCROLL)
+         {
+            if ((Wnd->ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+               Rect->left += UserGetSystemMetrics(SM_CXVSCROLL);
+            else
+               Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
+         }
+         else if (Style & WS_HSCROLL)
+            Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
+      }
+
+      if (Rect->top > Rect->bottom)
+         Rect->bottom = Rect->top;
+
+      if (Rect->left > Rect->right)
+         Rect->right = Rect->left;
+   }
+   else
+   {
+      Rect->right = Rect->left;
+      Rect->bottom = Rect->top;
+   }
+
+   return Result;
+}
+
+static
+INT NC_DoNCActive(PWND Wnd)
+{
+   INT Ret = 0;
+
+   if ( IntGetSysColor(COLOR_CAPTIONTEXT) != IntGetSysColor(COLOR_INACTIVECAPTIONTEXT) ||
+        IntGetSysColor(COLOR_ACTIVECAPTION) != IntGetSysColor(COLOR_INACTIVECAPTION) )
+       Ret = DC_CAPTION;
+
+   if (!(Wnd->style & WS_MINIMIZED) && UserHasThickFrameStyle(Wnd->style, Wnd->ExStyle))
+   {
+      //if (IntGetSysColor(COLOR_ACTIVEBORDER) != IntGetSysColor(COLOR_INACTIVEBORDER)) // Why are these the same?
+      {
+          Ret = DC_FRAME;
+      }
+   }
+   return Ret;
+}
+
+LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam )
+{
+   INT Flags;
+  /* Lotus Notes draws menu descriptions in the caption of its main
+   * window. When it wants to restore original "system" view, it just
+   * sends WM_NCACTIVATE message to itself. Any optimizations here in
+   * attempt to minimize redrawings lead to a not restored caption.
+   */
+   if (wParam & DC_ACTIVE)
+   {
+      Wnd->state |= WNDS_ACTIVEFRAME|WNDS_HASCAPTION;
+      wParam = DC_CAPTION|DC_ACTIVE;
+   }
+   else
+   {
+      Wnd->state &= ~(WNDS_ACTIVEFRAME|WNDS_HASCAPTION);
+      wParam = DC_CAPTION;
+   }
+
+   if (Wnd->state & WNDS_NONCPAINT || !(Wnd->style & WS_VISIBLE))
+      return 0;
+
+   /* This isn't documented but is reproducible in at least XP SP2 and
+    * Outlook 2007 depends on it
+    */
+   // MSDN:
+   // If this parameter is set to -1, DefWindowProc does not repaint the
+   // nonclient area to reflect the state change.
+   if ( lParam != -1 &&
+        ( Flags = NC_DoNCActive(Wnd)) != 0 )
+   {
+      HDC hDC;
+      HRGN hRgnTemp = NULL, hRgn = (HRGN)lParam;
+
+      if (GreIsHandleValid(hRgn))
+      {
+         hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
+         if (NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY) == ERROR)
+         {
+            GreDeleteObject(hRgnTemp);
+            hRgnTemp = NULL;
+         }
+      }
+
+      if ((hDC = UserGetDCEx(Wnd, hRgnTemp, DCX_WINDOW|DCX_USESTYLE)))
+      {
+         NC_DoNCPaint(Wnd, hDC, wParam | Flags); // Redraw MENUs.
+         UserReleaseDC(Wnd, hDC, FALSE);
+      }
+      else
+         GreDeleteObject(hRgnTemp);
+   }
+
+   return TRUE;
+}
+
+VOID
+NC_DoButton(PWND pWnd, WPARAM wParam, LPARAM lParam)
+{
+   MSG Msg;
+   HDC WindowDC;
+   BOOL Pressed = TRUE, OldState;
+   WPARAM SCMsg;
+   PMENU SysMenu;
+   ULONG ButtonType;
+   DWORD Style;
+   UINT MenuState;
+
+   Style = pWnd->style;
+   switch (wParam)
+   {
+      case HTCLOSE:
+         SysMenu = IntGetSystemMenu(pWnd, FALSE);
+         MenuState = IntGetMenuState(UserHMGetHandle(SysMenu), SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
+         if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (pWnd->style & CS_NOCLOSE))
+            return;
+         ButtonType = DFCS_CAPTIONCLOSE;
+         SCMsg = SC_CLOSE;
+         break;
+      case HTMINBUTTON:
+         if (!(Style & WS_MINIMIZEBOX))
+            return;
+         ButtonType = DFCS_CAPTIONMIN;
+         SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
+         break;
+      case HTMAXBUTTON:
+         if (!(Style & WS_MAXIMIZEBOX))
+            return;
+         ButtonType = DFCS_CAPTIONMAX;
+         SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
+         break;
+
+      default:
+         ASSERT(FALSE);
+         return;
+   }
+
+   /*
+    * FIXME: Not sure where to do this, but we must flush the pending
+    * window updates when someone clicks on the close button and at
+    * the same time the window is overlapped with another one. This
+    * looks like a good place for now...
+    */
+   co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
+
+   WindowDC = UserGetWindowDC(pWnd);
+   UserDrawCaptionButtonWnd(pWnd, WindowDC, TRUE, ButtonType);
+
+   co_UserSetCapture(UserHMGetHandle(pWnd));
+
+   for (;;)
+   {
+      if (co_IntGetPeekMessage(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE) <= 0)
+         break;
+      if (IntCallMsgFilter( &Msg, MSGF_MAX )) continue;
+
+      if (Msg.message == WM_LBUTTONUP)
+         break;
+
+      if (Msg.message != WM_MOUSEMOVE)
+         continue;
+
+      OldState = Pressed;
+      Pressed = (GetNCHitEx(pWnd, Msg.pt) == wParam);
+      if (Pressed != OldState)
+         UserDrawCaptionButtonWnd(pWnd, WindowDC, Pressed, ButtonType);
+   }
+
+   if (Pressed)
+      UserDrawCaptionButtonWnd(pWnd, WindowDC, FALSE, ButtonType);
+   IntReleaseCapture();
+   UserReleaseDC(pWnd, WindowDC, FALSE);
+   if (Pressed)
+      co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SCMsg, SCMsg == SC_CLOSE ? lParam : MAKELONG(Msg.pt.x,Msg.pt.y));
+}
+
+
+LRESULT
+NC_HandleNCLButtonDown(PWND pWnd, WPARAM wParam, LPARAM lParam)
+{
+    switch (wParam)
+    {
+        case HTCAPTION:
+        {
+            PWND TopWnd = pWnd, parent;
+            while(1)
+            {
+                if ((TopWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
+                    break;
+                parent = UserGetAncestor( TopWnd, GA_PARENT );
+                if (!parent || parent == UserGetDesktopWindow()) break;
+                TopWnd = parent;
+            }
+
+            if ( co_IntSetForegroundWindowMouse(TopWnd) ||
+                 //NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
+                 UserGetActiveWindow() == UserHMGetHandle(TopWnd))
+            {
+               co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
+            }
+            break;
+        }
+        case HTSYSMENU:
+        {
+          LONG style = pWnd->style;
+          if (style & WS_SYSMENU)
+          {
+              if(!(style & WS_MINIMIZE) )
+              {
+                RECT rect;
+                HDC hDC = UserGetWindowDC(pWnd);
+                UserGetInsideRectNC(pWnd, &rect);
+                UserDrawSysMenuButton(pWnd, hDC, &rect, TRUE);
+                UserReleaseDC( pWnd, hDC, FALSE );
+              }
+             co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam);
+         }
+         break;
+        }
+        case HTMENU:
+        {
+            co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
+            break;
+        }
+        case HTHSCROLL:
+        {
+            co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
+            break;
+        }
+        case HTVSCROLL:
+        {
+            co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
+            break;
+        }
+        case HTMINBUTTON:
+        case HTMAXBUTTON:
+        case HTCLOSE:
+        {
+          NC_DoButton(pWnd, wParam, lParam);
+          break;
+        }
+        case HTLEFT:
+        case HTRIGHT:
+        case HTTOP:
+        case HTBOTTOM:
+        case HTTOPLEFT:
+        case HTTOPRIGHT:
+        case HTBOTTOMLEFT:
+        case HTBOTTOMRIGHT:
+        {
+           /* Old comment:
+            * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
+            * This was previously done by setting wParam=SC_SIZE + wParam - 2
+            */
+           /* But that is not what WinNT does. Instead it sends this. This
+            * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
+            * SC_MOUSEMENU into wParam.
+            */
+            co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
+            break;
+        }
+        case HTBORDER:
+            break;
+    }
+    return(0);
+}
+
+
+LRESULT
+NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam)
+{
+  ULONG Style;
+
+  Style = pWnd->style;
+  switch(wParam)
+  {
+    case HTCAPTION:
+    {
+      /* Maximize/Restore the window */
+      if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
+      {
+        co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
+      }
+      break;
+    }
+    case HTSYSMENU:
+    {
+      PMENU SysMenu = IntGetSystemMenu(pWnd, FALSE);
+      UINT state = IntGetMenuState(UserHMGetHandle(SysMenu), SC_CLOSE, MF_BYCOMMAND);
+                  
+      /* If the close item of the sysmenu is disabled or not present do nothing */
+      if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
+          break;
+
+      co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam);
+      break;
+    }
+    default:
+      return NC_HandleNCLButtonDown(pWnd, wParam, lParam);
+  }
+  return(0);
+}
+
+/***********************************************************************
+ *           NC_HandleNCRButtonDown
+ *
+ * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
+ */
+LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam ) 
+{
+  MSG msg;
+  INT hittest = wParam;
+
+  switch (hittest)
+  {
+  case HTCAPTION:
+  case HTSYSMENU:
+      if (!IntGetSystemMenu( pwnd, FALSE )) break;
+
+      co_UserSetCapture( UserHMGetHandle(pwnd) );
+      for (;;)
+      {
+          if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
+          if (IntCallMsgFilter( &msg, MSGF_MAX )) continue;
+          if (msg.message == WM_RBUTTONUP)
+          {
+             hittest = GetNCHitEx( pwnd, msg.pt );
+             break;
+          }
+          if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0;
+      }
+      IntReleaseCapture();
+      if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL)
+      {
+         TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
+         co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y));
+      }
+      break;
+  }
+  return 0;
+}
+
+
 DWORD FASTCALL
 GetNCHitEx(PWND pWnd, POINT pt)
 {
index 4338a89..ab31fb8 100644 (file)
@@ -921,23 +921,6 @@ NtUserCtxDisplayIOCtl(
     return 0;
 }
 
-/*
- * @unimplemented
- */
-DWORD
-APIENTRY
-NtUserDrawMenuBarTemp(
-   HWND hWnd,
-   HDC hDC,
-   PRECT hRect,
-   HMENU hMenu,
-   HFONT hFont)
-{
-   /* We'll use this function just for caching the menu bar */
-   STUB
-   return 0;
-}
-
 /*
  * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
  */
@@ -1013,35 +996,6 @@ NtUserUpdateLayeredWindow(
    return 0;
 }
 
-/*
- * @unimplemented
- */
-BOOL APIENTRY
-NtUserEndMenu(VOID)
-{
-   STUB
-
-   return 0;
-}
-
-/*
- * @implemented
- */
-/* NOTE: unused function */
-BOOL APIENTRY
-NtUserTrackPopupMenuEx(
-   HMENU hMenu,
-   UINT fuFlags,
-   int x,
-   int y,
-   HWND hWnd,
-   LPTPMPARAMS lptpm)
-{
-   STUB
-
-   return FALSE;
-}
-
 DWORD APIENTRY
 NtUserQuerySendMessage(DWORD Unknown0)
 {
index cf90a7c..1a8d63b 100644 (file)
@@ -1865,8 +1865,6 @@ CLEANUP:
    END_CLEANUP;
 }
 
-static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
-
 BOOL
 UserDrawCaptionText(
    PWND pWnd,
@@ -1884,7 +1882,6 @@ UserDrawCaptionText(
    SIZE Size;
    BOOL Ret = TRUE;
    ULONG fit = 0, Length;
-   WCHAR szText[128];
    RECTL r = *lpRc;
 
    TRACE("UserDrawCaptionText: %wZ\n", Text);
@@ -1936,26 +1933,33 @@ UserDrawCaptionText(
    GreGetTextExtentExW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), r.right - r.left, &fit, 0, &Size, 0);
 
    Length = (Text->Length/sizeof(WCHAR) == fit ? fit : fit+1);
-   
-   RtlZeroMemory(&szText, sizeof(szText));
-   RtlCopyMemory(&szText, Text->Buffer, Text->Length);
 
-   if (Text->Length/sizeof(WCHAR) > Length && Length > 3)
+   if (Text->Length/sizeof(WCHAR) > Length)
    {
-      RtlCopyMemory(&szText[Length-3], ELLIPSISW, sizeof(ELLIPSISW));
       Ret = FALSE;
    }
 
-   GreExtTextOutW( hDc,
-                   lpRc->left,
-                   lpRc->top + (lpRc->bottom - lpRc->top) / 2 - Size.cy / 2, // DT_SINGLELINE && DT_VCENTER
-                   ETO_CLIPPED,
-                  (RECTL *)lpRc,
-                  (LPWSTR)&szText,
-                   Length,
-                   NULL,
-                   0 );
-
+   if (Ret)
+   {  // Faster while in setup.
+      GreExtTextOutW( hDc,
+                      lpRc->left,
+                      lpRc->top + (lpRc->bottom - lpRc->top) / 2 - Size.cy / 2, // DT_SINGLELINE && DT_VCENTER
+                      ETO_CLIPPED,
+                     (RECTL *)lpRc,
+                      Text->Buffer,
+                      Length,
+                      NULL,
+                      0 );
+   }
+   else
+   {
+      DrawTextW( hDc,
+                 Text->Buffer,
+                 Text->Length/sizeof(WCHAR),
+                (RECTL *)&r,
+                 DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_LEFT);
+   }
    IntGdiSetTextColor(hDc, OldTextColor);
 
    if (hOldFont)
@@ -2209,8 +2213,26 @@ NtUserDrawCaptionTemp(
    if (str != NULL)
       Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, &SafeStr, uFlags);
    else
+   {
+      if ( RECTL_bIsEmptyRect(&SafeRect) && hFont == 0 && hIcon == 0 )
+      {
+         Ret = TRUE;
+         if (uFlags & DC_DRAWCAPTIONMD)
+         {
+            ERR("NC Caption Mode\n");
+            UserDrawCaptionBar(pWnd, hDC, uFlags);
+            goto Exit;
+         }
+         else if (uFlags & DC_DRAWFRAMEMD)
+         {
+            ERR("NC Paint Mode\n");
+            NC_DoNCPaint(pWnd, hDC, uFlags); // Update Menus too!
+            goto Exit;
+         }
+      }
       Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, NULL, uFlags);
-
+   }
+Exit:
    UserLeave();
    return Ret;
 }
@@ -2222,7 +2244,7 @@ NtUserDrawCaption(HWND hWnd,
    LPCRECT lpRc,
    UINT uFlags)
 {
-       return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
+   return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
 }
 
 BOOL
index 307ddbd..e70183b 100644 (file)
@@ -33,4 +33,6 @@ HDC FASTCALL IntBeginPaint(PWND,PPAINTSTRUCT);
 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND );
 BOOL FASTCALL IntFlashWindowEx(PWND,PFLASHWINFO);
 BOOL FASTCALL IntIntersectWithParents(PWND, RECTL *);
-BOOL FASTCALL IntIsWindowDrawable(PWND);
\ No newline at end of file
+BOOL FASTCALL IntIsWindowDrawable(PWND);
+BOOL UserDrawCaption(PWND,HDC,RECTL*,HFONT,HICON,const PUNICODE_STRING,UINT);
+
index 57423c4..6fe9c5d 100644 (file)
@@ -39,5 +39,11 @@ typedef struct _SBINFOEX
 #define SBOBJ_TO_SBID(Obj)     ((Obj) - OBJID_HSCROLL)
 #define SBID_IS_VALID(id)      (id == SB_HORZ || id == SB_VERT || id == SB_CTL)
 
-BOOL FASTCALL co_IntCreateScrollBars(PWND Window);
-BOOL FASTCALL IntDestroyScrollBars(PWND Window);
+BOOL FASTCALL co_IntCreateScrollBars(PWND);
+BOOL FASTCALL IntDestroyScrollBars(PWND);
+DWORD FASTCALL co_UserShowScrollBar(PWND,int,BOOL,BOOL);
+BOOL FASTCALL co_IntGetScrollBarInfo(PWND,LONG,PSCROLLBARINFO);
+BOOL FASTCALL co_IntSetScrollBarInfo(PWND,LONG,PSETSCROLLBARINFO);
+void IntDrawScrollBar(PWND,HDC,INT);
+BOOL FASTCALL IntScrollWindow(PWND,int,int,CONST RECT*,CONST RECT*);
+DWORD FASTCALL IntScrollWindowEx(PWND,INT,INT,const RECT*,const RECT*,HRGN,LPRECT,UINT);
index 1cdff4a..462690b 100644 (file)
 #include <win32k.h>
 DBG_DEFAULT_CHANNEL(UserScrollbar);
 
+/* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */
+#define SCROLL_NOWHERE         0x00    /* Outside the scroll bar */
+#define SCROLL_TOP_ARROW       0x01    /* Top or left arrow */
+#define SCROLL_TOP_RECT                0x02    /* Rectangle between the top arrow and the thumb */
+#define SCROLL_THUMB           0x03    /* Thumb rectangle */
+#define SCROLL_BOTTOM_RECT     0x04    /* Rectangle between the thumb and the bottom arrow */
+#define SCROLL_BOTTOM_ARROW    0x05    /* Bottom or right arrow */
+
+#define SCROLL_FIRST_DELAY   200        /* Delay (in ms) before first repetition when
+                                           holding the button down */
+#define SCROLL_REPEAT_DELAY  50         /* Delay (in ms) between scroll repetitions */
+
+#define SCROLL_TIMER   0                /* Scroll timer id */
+
+  /* Minimum size of the rectangle between the arrows */
+#define SCROLL_MIN_RECT  4
+
+  /* Minimum size of the thumb in pixels */
+#define SCROLL_MIN_THUMB 6
+
+  /* Overlap between arrows and thumb */
+#define SCROLL_ARROW_THUMB_OVERLAP 0
+
+//
+//
+//
 #define MINTRACKTHUMB    8               /* Minimum size of the rectangle between the arrows */
 
  /* What to do after SetScrollInfo() */
@@ -554,6 +580,39 @@ co_IntGetScrollBarInfo(PWND Window, LONG idObject, PSCROLLBARINFO psbi)
    return TRUE;
 }
 
+BOOL FASTCALL
+co_IntSetScrollBarInfo(PWND Window, LONG idObject, PSETSCROLLBARINFO psbi)
+{
+   INT Bar;
+   PSCROLLBARINFO sbi;
+   LPSCROLLINFO psi;
+   ASSERT_REFS_CO(Window);
+
+   Bar = SBOBJ_TO_SBID(idObject);
+
+   if(!SBID_IS_VALID(Bar))
+   {
+      EngSetLastError(ERROR_INVALID_PARAMETER);
+      ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
+      return FALSE;
+   }
+
+   if(!co_IntCreateScrollBars(Window))
+   {
+      ERR("Failed to create scrollbars for window.\n");
+      return FALSE;
+   }
+
+   sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
+   psi = IntGetScrollInfoFromWindow(Window, Bar);
+
+   psi->nTrackPos = psbi->nTrackPos;
+   sbi->reserved  = psbi->reserved;
+   RtlCopyMemory(&sbi->rgstate, &psbi->rgstate, sizeof(psbi->rgstate));
+
+   return TRUE;
+}
+
 BOOL FASTCALL
 co_IntCreateScrollBars(PWND Window)
 {
@@ -709,6 +768,248 @@ co_UserShowScrollBar(PWND Wnd, int nBar, BOOL fShowH, BOOL fShowV)
    return FALSE;
 }
 
+static void
+IntDrawScrollInterior(PWND pWnd, HDC hDC, INT nBar, BOOL Vertical, PSCROLLBARINFO ScrollBarInfo)
+{
+   INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
+   INT ThumbTop = ScrollBarInfo->xyThumbTop;
+   RECT Rect;
+   HBRUSH hSaveBrush, hBrush;
+   BOOL TopSelected = FALSE, BottomSelected = FALSE;
+
+   if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
+      TopSelected = TRUE;
+   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
+      BottomSelected = TRUE;
+
+   /*
+    * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
+    * The window-owned scrollbars need to call DefWndControlColor
+    * to correctly setup default scrollbar colors
+    */
+   if (nBar == SB_CTL)
+   {
+      hBrush = GetControlBrush( pWnd, hDC, WM_CTLCOLORSCROLLBAR);
+      if (!hBrush)
+         hBrush = IntGetSysColorBrush(COLOR_SCROLLBAR);
+   }
+   else
+   {
+      hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
+   }
+
+   hSaveBrush = NtGdiSelectBrush(hDC, hBrush);
+
+   /* Calculate the scroll rectangle */
+   if (Vertical)
+   {
+      Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
+      Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
+      Rect.left = ScrollBarInfo->rcScrollBar.left;
+      Rect.right = ScrollBarInfo->rcScrollBar.right;
+   }
+   else
+   {
+      Rect.top = ScrollBarInfo->rcScrollBar.top;
+      Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
+      Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
+      Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
+   }
+
+   /* Draw the scroll rectangles and thumb */
+   if (!ScrollBarInfo->xyThumbBottom)
+   {
+      NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
+         Rect.bottom - Rect.top, PATCOPY);
+
+      /* Cleanup and return */
+      NtGdiSelectBrush(hDC, hSaveBrush);
+      return;
+   }
+
+   ThumbTop -= ScrollBarInfo->dxyLineButton;
+
+   if (ScrollBarInfo->dxyLineButton)
+   {
+      if (Vertical)
+      {
+         if (ThumbSize)
+         {
+            NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
+                   ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
+            Rect.top += ThumbTop;
+            NtGdiPatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
+               Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
+            Rect.bottom = Rect.top + ThumbSize;
+         }
+         else
+         {
+            if (ThumbTop)
+            {
+               NtGdiPatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
+                  Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
+            }
+         }
+      }
+      else
+      {
+         if (ThumbSize)
+         {
+            NtGdiPatBlt(hDC, Rect.left, Rect.top, ThumbTop,
+               Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
+            Rect.left += ThumbTop;
+            NtGdiPatBlt(hDC, Rect.left + ThumbSize, Rect.top,
+               Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
+               BottomSelected ? BLACKNESS : PATCOPY);
+            Rect.right = Rect.left + ThumbSize;
+         }
+         else
+         {
+            if (ThumbTop)
+            {
+               NtGdiPatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
+                  Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
+            }
+         }
+      }
+   }
+
+   /* Draw the thumb */
+   if (ThumbSize)
+      DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
+
+   /* Cleanup */
+   NtGdiSelectBrush(hDC, hSaveBrush);
+}
+
+
+static VOID FASTCALL
+IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
+{
+   RECT RectLT, RectRB;
+   INT ScrollDirFlagLT, ScrollDirFlagRB;
+
+   RectLT = RectRB = ScrollBarInfo->rcScrollBar;
+   if (Vertical)
+   {
+      ScrollDirFlagLT = DFCS_SCROLLUP;
+      ScrollDirFlagRB = DFCS_SCROLLDOWN;
+      RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
+      RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
+   }
+   else
+   {
+      ScrollDirFlagLT = DFCS_SCROLLLEFT;
+      ScrollDirFlagRB = DFCS_SCROLLRIGHT;
+      RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
+      RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
+   }
+
+   if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
+   {
+      ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
+   }
+   if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
+   {
+      ScrollDirFlagLT |= DFCS_INACTIVE;
+   }
+   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
+   {
+      ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
+   }
+   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
+   {
+      ScrollDirFlagRB |= DFCS_INACTIVE;
+   }
+
+   DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
+   DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
+}
+
+static LONG FASTCALL
+IntScrollGetObjectId(INT SBType)
+{
+   if (SBType == SB_VERT)
+       return OBJID_VSCROLL;
+   if (SBType == SB_HORZ)
+       return OBJID_HSCROLL;
+   return OBJID_CLIENT;
+}
+
+void
+IntDrawScrollBar(PWND Wnd, HDC DC, INT Bar)
+{
+   //PSBWND pSBWnd;
+   //INT ThumbSize;
+   PTHREADINFO pti;
+   SCROLLBARINFO Info;
+   BOOL Vertical;
+
+   pti = PsGetCurrentThreadWin32Thread();
+
+  /*
+   * Get scroll bar info.
+   */
+   switch (Bar)
+   {
+      case SB_HORZ:
+        Vertical = FALSE;
+        break;
+
+      case SB_VERT:
+        Vertical = TRUE;
+        break;
+
+      case SB_CTL:
+        Vertical = (Wnd->style & SBS_VERT) != 0;
+        break;
+
+      default:
+        return;
+   }
+
+   if (!co_IntGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), &Info))
+   {
+      return;
+   }
+
+   if (RECTL_bIsEmptyRect(&Info.rcScrollBar))
+   {
+      return;
+   }
+
+  //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
+
+  /*
+   * Draw the arrows.
+   */
+   if (Info.dxyLineButton)
+   {
+      IntDrawScrollArrows(DC, &Info, Vertical);
+   }
+
+  /*
+   * Draw the interior.
+   */
+   IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);
+
+  /*
+   * If scroll bar has focus, reposition the caret.
+   */
+   if ( Wnd == pti->MessageQueue->spwndFocus && Bar == SB_CTL )
+   {
+      if (Vertical)
+      {
+          co_IntSetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
+      }
+      else
+      {
+          co_IntSetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
+      }
+   }
+}
+
+
 LRESULT APIENTRY
 ScrollBarWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {
index e0cd635..64576ec 100644 (file)
@@ -226,6 +226,241 @@ UserScrollDC(
    return Result;
 }
 
+DWORD
+FASTCALL
+IntScrollWindowEx(
+   PWND Window,
+   INT dx,
+   INT dy,
+   const RECT *prcScroll,
+   const RECT *prcClip,
+   HRGN hrgnUpdate,
+   LPRECT prcUpdate,
+   UINT flags)
+{
+   RECTL rcScroll, rcClip, rcCaret;
+   INT Result;
+   PWND CaretWnd;
+   HDC hDC;
+   PREGION RgnUpdate = NULL, RgnTemp, RgnWinupd = NULL;
+   HWND hwndCaret;
+   DWORD dcxflags = 0;
+   int rdw_flags;
+   USER_REFERENCE_ENTRY CaretRef;
+
+   IntGetClientRect(Window, &rcClip);
+
+   if (prcScroll)
+   {
+      RECTL_bIntersectRect(&rcScroll, &rcClip, prcScroll);
+   }
+   else
+      rcScroll = rcClip;
+
+   if (prcClip)
+   {
+      RECTL_bIntersectRect(&rcClip, &rcClip, prcClip);
+   }
+
+   if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top ||
+         (dx == 0 && dy == 0))
+   {
+      return NULLREGION;
+   }
+
+   /* We must use a copy of the region, as we can't hold an exclusive lock
+    * on it while doing callouts to user-mode */
+   RgnUpdate = IntSysCreateRectpRgn(0, 0, 0, 0);
+   if(!RgnUpdate)
+   {
+       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       return ERROR;
+   }
+
+   if (hrgnUpdate)
+   {
+       RgnTemp = REGION_LockRgn(hrgnUpdate);
+       if (!RgnTemp)
+       {
+           EngSetLastError(ERROR_INVALID_HANDLE);
+           return ERROR;
+       }
+       IntGdiCombineRgn(RgnUpdate, RgnTemp, NULL, RGN_COPY);
+       REGION_UnlockRgn(RgnTemp);
+   }
+
+   /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
+   if (flags & SW_SCROLLWNDDCE)
+   {
+      dcxflags = DCX_USESTYLE;
+
+      if (!(Window->pcls->style & (CS_OWNDC|CS_CLASSDC)))
+         dcxflags |= DCX_CACHE; // AH??? wine~ If not Powned or with Class go Cheap!
+
+      if (flags & SW_SCROLLCHILDREN && Window->style & WS_CLIPCHILDREN)
+         dcxflags |= DCX_CACHE|DCX_NOCLIPCHILDREN;
+   }
+   else
+   {
+       /* So in this case ScrollWindowEx uses Cache DC. */
+       dcxflags = DCX_CACHE|DCX_USESTYLE;
+       if (flags & SW_SCROLLCHILDREN) dcxflags |= DCX_NOCLIPCHILDREN;
+   }
+
+   hDC = UserGetDCEx(Window, 0, dcxflags);
+   if (!hDC)
+   {
+      /* FIXME: SetLastError? */
+      return ERROR;
+   }
+
+   rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
+
+   rcCaret = rcScroll;
+   hwndCaret = co_IntFixCaret(Window, &rcCaret, flags);
+
+   Result = UserScrollDC( hDC,
+                          dx,
+                          dy,
+                          &rcScroll,
+                          &rcClip,
+                          NULL,
+                          RgnUpdate,
+                          prcUpdate);
+
+   UserReleaseDC(Window, hDC, FALSE);
+
+   /*
+    * Take into account the fact that some damage may have occurred during
+    * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
+    */
+
+   RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
+   if (!RgnTemp)
+   {
+       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       return ERROR;
+   }
+
+   if (co_IntGetUpdateRgn(Window, RgnTemp, FALSE) != NULLREGION)
+   {
+      PREGION RgnClip = IntSysCreateRectpRgnIndirect(&rcClip);
+      if (RgnClip)
+      {
+          if (hrgnUpdate)
+          {
+             RgnWinupd = IntSysCreateRectpRgn( 0, 0, 0, 0);
+             IntGdiCombineRgn( RgnWinupd, RgnTemp, 0, RGN_COPY);
+          }
+
+          REGION_bOffsetRgn(RgnTemp, dx, dy);
+
+          IntGdiCombineRgn(RgnTemp, RgnTemp, RgnClip, RGN_AND);
+
+          if (hrgnUpdate)
+              IntGdiCombineRgn( RgnWinupd, RgnWinupd, RgnTemp, RGN_OR );
+
+          co_UserRedrawWindow(Window, NULL, RgnTemp, rdw_flags );
+
+          REGION_Delete(RgnClip);
+      }
+   }
+   REGION_Delete(RgnTemp);
+
+   if (flags & SW_SCROLLCHILDREN)
+   {
+      PWND Child;
+      RECTL rcChild;
+      POINT ClientOrigin;
+      USER_REFERENCE_ENTRY WndRef;
+      RECTL rcDummy;
+      LPARAM lParam;
+
+      IntGetClientOrigin(Window, &ClientOrigin);
+
+      for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
+      {
+         rcChild = Child->rcWindow;
+         rcChild.left -= ClientOrigin.x;
+         rcChild.top -= ClientOrigin.y;
+         rcChild.right -= ClientOrigin.x;
+         rcChild.bottom -= ClientOrigin.y;
+
+         if (!prcScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll))
+         {
+            UserRefObjectCo(Child, &WndRef);
+
+            if (Window->spwndParent == UserGetDesktopWindow()) // Window->spwndParent->fnid == FNID_DESKTOP )
+               lParam = MAKELONG(Child->rcClient.left, Child->rcClient.top);
+            else
+               lParam = MAKELONG(rcChild.left + dx, rcChild.top + dy);
+
+            /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
+            /* windows sometimes a WM_MOVE */                  
+            co_IntSendMessage(UserHMGetHandle(Child), WM_MOVE, 0, lParam);
+            
+            UserDerefObjectCo(Child);
+         }
+      }
+   }
+
+   if (flags & (SW_INVALIDATE | SW_ERASE))
+   {
+      co_UserRedrawWindow( Window,
+                           NULL,
+                           RgnUpdate,
+                           rdw_flags |                                    /*    HACK    */
+                          ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : RDW_NOCHILDREN) );
+   }
+
+   if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
+   {
+      UserRefObjectCo(CaretWnd, &CaretRef);
+
+      co_IntSetCaretPos(rcCaret.left + dx, rcCaret.top + dy);
+      co_UserShowCaret(CaretWnd);
+
+      UserDerefObjectCo(CaretWnd);
+   }
+
+   if (hrgnUpdate && (Result != ERROR))
+   {
+       /* Give everything back to the caller */
+       RgnTemp = REGION_LockRgn(hrgnUpdate);
+       /* The handle should still be valid */
+       ASSERT(RgnTemp);
+       if (RgnWinupd)
+           IntGdiCombineRgn(RgnTemp, RgnUpdate, RgnWinupd, RGN_OR);
+       else
+           IntGdiCombineRgn(RgnTemp, RgnUpdate, NULL, RGN_COPY);
+       REGION_UnlockRgn(RgnTemp);
+   }
+
+   if (RgnWinupd)
+   {
+       REGION_Delete(RgnWinupd);
+   }
+
+   if (RgnUpdate)
+   {
+      REGION_Delete(RgnUpdate);
+   }
+
+   return Result;
+}
+
+
+BOOL FASTCALL
+IntScrollWindow(PWND pWnd,
+                int dx,
+                int dy,
+                CONST RECT *lpRect,
+                CONST RECT *prcClip)
+{
+   return IntScrollWindowEx( pWnd, dx, dy, lpRect, prcClip, 0, NULL,
+                            (lpRect ? 0 : SW_SCROLLCHILDREN) | (SW_ERASE|SW_INVALIDATE|SW_SCROLLWNDDCE)) != ERROR;
+}
+
 /*
  * NtUserScrollDC
  *
index 2f0e386..2addad1 100644 (file)
@@ -2,7 +2,12 @@
 
 FORCEINLINE PMENU UserGetMenuObject(HMENU hMenu)
 {
-   return UserGetObject(gHandleTable, hMenu, TYPE_MENU);
+   PMENU pMenu = UserGetObject(gHandleTable, hMenu, TYPE_MENU);
+   if (!pMenu)
+   {
+      EngSetLastError(ERROR_INVALID_MENU_HANDLE);
+   }
+   return pMenu;
 }
 
 #define ASSERT_REFS_CO(_obj_) \
@@ -97,14 +102,11 @@ UserSystemParametersInfo(
 VOID FASTCALL IntSetWindowState(PWND, UINT);
 VOID FASTCALL IntClearWindowState(PWND, UINT);
 PTHREADINFO FASTCALL IntTID2PTI(HANDLE);
+HBRUSH FASTCALL GetControlBrush(PWND pwnd,HDC  hdc,UINT ctlType);
 
 /*************** MESSAGE.C ***************/
 
-BOOL FASTCALL
-UserPostMessage(HWND Wnd,
-        UINT Msg,
-        WPARAM wParam,
-        LPARAM lParam);
+BOOL FASTCALL UserPostMessage(HWND Wnd,UINT Msg, WPARAM wParam, LPARAM lParam);
 
 /*************** WINDOW.C ***************/
 
@@ -114,6 +116,8 @@ HWND FASTCALL UserGetShellWindow(VOID);
 HDC FASTCALL UserGetDCEx(PWND Window OPTIONAL, HANDLE ClipRegion, ULONG Flags);
 BOOLEAN co_UserDestroyWindow(PVOID Object);
 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type);
+BOOL APIENTRY DefSetText(PWND Wnd, PCWSTR WindowText);
+DWORD FASTCALL IntGetWindowContextHelpId( PWND pWnd );
 
 /*************** MENU.C ***************/
 
@@ -121,12 +125,24 @@ HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu);
 BOOL FASTCALL UserSetMenuDefaultItem(PMENU Menu, UINT uItem, UINT fByPos);
 BOOL FASTCALL UserDestroyMenu(HMENU hMenu);
 
-/*************** SCROLLBAR.C ***************/
-
-DWORD FASTCALL co_UserShowScrollBar(PWND Wnd, int nBar, BOOL fShowH, BOOL fShowV);
-
 /************** NONCLIENT **************/
 
 VOID FASTCALL DefWndDoSizeMove(PWND pwnd, WORD wParam);
+LRESULT NC_DoNCPaint(PWND,HDC,INT);
+void FASTCALL NC_GetSysPopupPos(PWND, RECT *);
+LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam );
+LRESULT NC_HandleNCCalcSize( PWND wnd, WPARAM wparam, RECTL *winRect );
+VOID NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle);
+VOID UserDrawCaptionBar( PWND pWnd, HDC hDC, INT Flags);
+void UserGetInsideRectNC(PWND Wnd, RECT *rect);
+LRESULT NC_HandleNCLButtonDown(PWND Wnd, WPARAM wParam, LPARAM lParam);
+LRESULT NC_HandleNCLButtonDblClk(PWND Wnd, WPARAM wParam, LPARAM lParam);
+LRESULT NC_HandleNCRButtonDown( PWND wnd, WPARAM wParam, LPARAM lParam );
+
+/************** DEFWND **************/
+
+HBRUSH FASTCALL DefWndControlColor(HDC hDC,UINT ctlType);
+BOOL UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down);
+BOOL UserPaintCaption(PWND pWnd, INT Flags);
 
 /* EOF */
index 2dad834..ac5053c 100644 (file)
@@ -52,8 +52,6 @@ extern HANDLE hModuleWin;    // This Win32k Instance.
 extern struct _CLS *SystemClassList;
 extern BOOL RegisteredSysClasses;
 
-typedef struct tagMENUSTATE MENUSTATE, *PMENUSTATE;
-
 #include <pshpack1.h>
 // FIXME: Move to ntuser.h
 typedef struct _TL
@@ -110,7 +108,7 @@ typedef struct _THREADINFO
     HDESK               hdesk;
     UINT                cPaintsReady; /* Count of paints pending. */
     UINT                cTimersReady; /* Count of timers pending. */
-    PMENUSTATE          pMenuState;
+    struct tagMENUSTATE* pMenuState;
     DWORD               dwExpWinVer;
     DWORD               dwCompatFlags;
     DWORD               dwCompatFlags2;
index 6de81b4..d63ec08 100644 (file)
@@ -65,9 +65,12 @@ PWND FASTCALL VerifyWnd(PWND pWnd)
 {
    HWND hWnd;
    UINT State, State2;
+   ULONG Error;
 
    if (!pWnd) return NULL;
 
+   Error = EngGetLastError();
+
    _SEH2_TRY
    {
       hWnd = UserHMGetHandle(pWnd);
@@ -76,6 +79,7 @@ PWND FASTCALL VerifyWnd(PWND pWnd)
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
+      EngSetLastError(Error);
       _SEH2_YIELD(return NULL);
    }
    _SEH2_END
@@ -83,8 +87,9 @@ PWND FASTCALL VerifyWnd(PWND pWnd)
    if ( UserObjectInDestroy(hWnd) ||
         State & WNDS_DESTROYED ||
         State2 & WNDS2_INDESTROY )
-      return NULL;
+      pWnd = NULL;
 
+   EngSetLastError(Error);
    return pWnd;
 }
 
@@ -362,6 +367,20 @@ IntGetWindow(HWND hWnd,
     return Ret;
 }
 
+DWORD FASTCALL IntGetWindowContextHelpId( PWND pWnd )
+{
+   PPROPERTY HelpId;
+
+   do
+   {
+      HelpId = IntGetProp(pWnd, gpsi->atomContextHelpIdProp);
+      if (!HelpId) break;
+      pWnd = IntGetParent(pWnd);
+   }
+   while (pWnd && pWnd->fnid != FNID_DESKTOP);
+   return (DWORD) (HelpId ? HelpId->Data : 0 );
+}
+
 /***********************************************************************
  *           IntSendDestroyMsg
  */
@@ -593,6 +612,7 @@ LRESULT co_UserFreeWindow(PWND Window,
         Window->IDMenu &&
         (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
    {
+      TRACE("UFW: IDMenu %p\n",Window->IDMenu);
       IntDestroyMenuObject(Menu, TRUE);
       Window->IDMenu = 0;
    }
@@ -3497,7 +3517,7 @@ co_IntSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi, BOOL bAlte
                                             Ansi);
          if (!OldValue) return 0;
       }
-*/
+ */
       *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
    }
    else
@@ -3913,6 +3933,78 @@ CLEANUP:
    END_CLEANUP;
 }
 
+BOOL APIENTRY
+DefSetText(PWND Wnd, PCWSTR WindowText)
+{
+   UNICODE_STRING UnicodeString;
+   BOOL Ret = FALSE;
+
+   RtlInitUnicodeString(&UnicodeString, WindowText);
+
+   if (UnicodeString.Length != 0)
+   {
+      if (Wnd->strName.MaximumLength > 0 &&
+          UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
+      {
+         ASSERT(Wnd->strName.Buffer != NULL);
+
+         Wnd->strName.Length = UnicodeString.Length;
+         Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
+         RtlCopyMemory(Wnd->strName.Buffer,
+                              UnicodeString.Buffer,
+                              UnicodeString.Length);
+      }
+      else
+      {
+         PWCHAR buf;
+         Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
+         buf = Wnd->strName.Buffer;
+         Wnd->strName.Buffer = NULL;
+         if (buf != NULL)
+         {
+            DesktopHeapFree(Wnd->head.rpdesk, buf);
+         }
+
+         Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
+                                                   UnicodeString.Length + sizeof(UNICODE_NULL));
+         if (Wnd->strName.Buffer != NULL)
+         {
+            Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
+            RtlCopyMemory(Wnd->strName.Buffer,
+                                 UnicodeString.Buffer,
+                                 UnicodeString.Length);
+            Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
+            Wnd->strName.Length = UnicodeString.Length;
+         }
+         else
+         {
+            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto Exit;
+         }
+      }
+   }
+   else
+   {
+      Wnd->strName.Length = 0;
+      if (Wnd->strName.Buffer != NULL)
+          Wnd->strName.Buffer[0] = L'\0';
+   }
+
+   // FIXME: HAX! Windows does not do this in here!
+   // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
+   // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
+   /* Send shell notifications */
+   if (!Wnd->spwndOwner && !IntGetParent(Wnd))
+   {
+      co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
+   }
+
+   Ret = TRUE;
+Exit:
+   if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
+   return Ret;
+}
+
 /*
  * NtUserDefSetText
  *
index 843f6e8..d377206 100644 (file)
@@ -55,6 +55,10 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
                                         PWND OwnerWindow,
                                         PVOID acbiBuffer,
                                         PDESKTOP pdeskCreated);
+PWND FASTCALL co_UserCreateWindowEx(CREATESTRUCTW* Cs,
+                                    PUNICODE_STRING ClassName,
+                                    PLARGE_STRING WindowName,
+                                    PVOID acbiBuffer);
 BOOL FASTCALL IntEnableWindow(HWND,BOOL);
 BOOL FASTCALL IntIsWindowVisible(PWND);
 DWORD FASTCALL GetNCHitEx(PWND,POINT);
index faf6790..8ba06b3 100644 (file)
@@ -2280,7 +2280,7 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
                     Cmd = SW_SHOWDEFAULT;
                }
                FirstTime = TRUE;
-               ERR("co_WPSW FT 1\n");
+               TRACE("co_WPSW FT 1\n");
             }
          }
       }
@@ -2292,7 +2292,7 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
       {
          Cmd = pti->ppi->usi.wShowWindow;
          FirstTime = TRUE;
-         ERR("co_WPSW FT 2\n");
+         TRACE("co_WPSW FT 2\n");
       }
    }
 
index 42694eb..03e1cd8 100644 (file)
@@ -69,3 +69,5 @@ PWND FASTCALL IntRealChildWindowFromPoint(PWND,LONG,LONG);
 BOOL FASTCALL IntScreenToClient(PWND,LPPOINT);
 BOOL FASTCALL IntClientToScreen(PWND,LPPOINT);
 BOOL FASTCALL IntGetWindowRect(PWND,RECTL*);
+BOOL UserHasWindowEdge(DWORD,DWORD);
+VOID UserGetWindowBorders(DWORD,DWORD,SIZE*,BOOL);
index 64b37cd..76ffa6d 100644 (file)
@@ -297,6 +297,9 @@ co_IntInitializeDesktopGraphics(VOID)
    /* Setup the icons */
    co_IntSetWndIcons();
 
+   /* Setup Menu */
+   MenuInit();
+
    /* Show the desktop */
    pdesk = IntGetActiveDesktop();
    ASSERT(pdesk);
diff --git a/reactos/win32ss/user/rtl/text.c b/reactos/win32ss/user/rtl/text.c
new file mode 100644 (file)
index 0000000..457a089
--- /dev/null
@@ -0,0 +1,1365 @@
+/*
+ *  ReactOS kernel
+ *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * PROJECT:         ReactOS user32.dll
+ * FILE:            win32ss/user/rtl/text.c
+ * PURPOSE:         Draw Text
+ * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ *      09-05-2001  CSH  Created
+ */
+
+/* INCLUDES ******************************************************************/
+
+#ifdef _WIN32K_
+#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserMenu);
+#else
+#include <user32.h>
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(text);
+#endif
+
+/* FUNCTIONS *****************************************************************/
+
+#ifndef NDEBUG
+
+#ifdef assert
+#undef assert
+#endif
+
+#define assert(e) ((e) ? (void)0 : _font_assert(#e, __FILE__, __LINE__))
+
+#else
+#include <assert.h>
+
+#endif
+
+void _font_assert(const char *msg, const char *file, int line)
+{
+  /* Assertion failed at foo.c line 45: x<y */
+  DbgPrint("Assertion failed at %s line %d: %s\n", file, line, msg);
+#ifdef _WIN32K_
+  ASSERT(FALSE);
+#else
+  ExitProcess(3);  
+  for(;;); /* eliminate warning by mingw */
+#endif
+}
+
+/***********************************************************************
+ *           TEXT_TabbedTextOut
+ *
+ * Helper function for TabbedTextOut() and GetTabbedTextExtent().
+ * Note: this doesn't work too well for text-alignment modes other
+ *       than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
+ */
+/* WINE synced 22-May-2006 */
+LONG TEXT_TabbedTextOut( HDC hdc,
+                         INT x,
+                         INT y,
+                         LPCWSTR lpstr,
+                         INT count,
+                         INT cTabStops,
+                         const INT *lpTabPos,
+                         INT nTabOrg,
+                         BOOL fDisplayText )
+{
+    INT defWidth;
+    SIZE extent;
+    int i, j;
+    int start = x;
+
+    if (!lpTabPos)
+        cTabStops=0;
+
+    if (cTabStops == 1)
+    {
+        defWidth = *lpTabPos;
+        cTabStops = 0;
+    }
+    else
+    {
+#ifdef _WIN32K_
+        TEXTMETRICW tm;
+        GreGetTextMetricsW( hdc, &tm );
+#else
+        TEXTMETRICA tm;
+        GetTextMetricsA( hdc, &tm );
+#endif
+        defWidth = 8 * tm.tmAveCharWidth;
+    }
+
+    while (count > 0)
+    {
+        RECT r;
+        INT x0;
+        x0 = x;
+        r.left = x0;
+        /* chop the string into substrings of 0 or more <tabs>
+         * possibly followed by 1 or more normal characters */
+        for (i = 0; i < count; i++)
+            if (lpstr[i] != '\t') break;
+        for (j = i; j < count; j++)
+            if (lpstr[j] == '\t') break;
+        /* get the extent of the normal character part */
+#ifdef _WIN32K_
+        GreGetTextExtentW( hdc, (LPWSTR)lpstr + i, j - i , &extent, 1 );
+#else
+        GetTextExtentPointW( hdc, lpstr + i, j - i , &extent );
+#endif
+        /* and if there is a <tab>, calculate its position */
+        if( i) {
+            /* get x coordinate for the drawing of this string */
+            for (; cTabStops > i; lpTabPos++, cTabStops--)
+            {
+                if( nTabOrg + abs( *lpTabPos) > x) {
+                    if( lpTabPos[ i - 1] >= 0) {
+                        /* a left aligned tab */
+                        x = nTabOrg + lpTabPos[ i-1] + extent.cx;
+                        break;
+                    }
+                    else
+                    {
+                        /* if tab pos is negative then text is right-aligned
+                         * to tab stop meaning that the string extends to the
+                         * left, so we must subtract the width of the string */
+                        if (nTabOrg - lpTabPos[ i - 1] - extent.cx > x)
+                        {
+                            x = nTabOrg - lpTabPos[ i - 1];
+                            x0 = x - extent.cx;
+                            break;
+                        }
+                    }
+                }
+            }
+            /* if we have run out of tab stops and we have a valid default tab
+             * stop width then round x up to that width */
+            if ((cTabStops <= i) && (defWidth > 0)) {
+                x0 = nTabOrg + ((x - nTabOrg) / defWidth + i) * defWidth;
+                x = x0 + extent.cx;
+            } else if ((cTabStops <= i) && (defWidth < 0)) {
+                x = nTabOrg + ((x - nTabOrg + extent.cx) / -defWidth + i)
+                    * -defWidth;
+                x0 = x - extent.cx;
+            }
+        } else
+            x += extent.cx;
+
+        if (fDisplayText)
+        {
+            r.top    = y;
+            r.right  = x;
+            r.bottom = y + extent.cy;
+#ifdef _WIN32K_
+            GreExtTextOutW( hdc, x0, y, GreGetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
+                         &r, (LPWSTR)lpstr + i, j - i, NULL, 0 );
+#else
+            ExtTextOutW( hdc, x0, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
+                         &r, lpstr + i, j - i, NULL );
+#endif
+        }
+        count -= j;
+        lpstr += j;
+    }
+    return MAKELONG(x - start, extent.cy);
+}
+
+/*********************************************************************
+ *
+ *            DrawText functions
+ *
+ * Copied from Wine.
+ *   Copyright 1993, 1994 Alexandre Julliard
+ *   Copyright 2002 Bill Medland
+ *
+ * Design issues
+ *   How many buffers to use
+ *     While processing in DrawText there are potentially three different forms
+ *     of the text that need to be held.  How are they best held?
+ *     1. The original text is needed, of course, to see what to display.
+ *     2. The text that will be returned to the user if the DT_MODIFYSTRING is
+ *        in effect.
+ *     3. The buffered text that is about to be displayed e.g. the current line.
+ *        Typically this will exclude the ampersands used for prefixing etc.
+ *
+ *     Complications.
+ *     a. If the buffered text to be displayed includes the ampersands then
+ *        we will need special measurement and draw functions that will ignore
+ *        the ampersands (e.g. by copying to a buffer without the prefix and
+ *        then using the normal forms).  This may involve less space but may
+ *        require more processing.  e.g. since a line containing tabs may
+ *        contain several underlined characters either we need to carry around
+ *        a list of prefix locations or we may need to locate them several
+ *        times.
+ *     b. If we actually directly modify the "original text" as we go then we
+ *        will need some special "caching" to handle the fact that when we
+ *        ellipsify the text the ellipsis may modify the next line of text,
+ *        which we have not yet processed.  (e.g. ellipsification of a W at the
+ *        end of a line will overwrite the W, the \n and the first character of
+ *        the next line, and a \0 will overwrite the second.  Try it!!)
+ *
+ *     Option 1.  Three separate storages. (To be implemented)
+ *       If DT_MODIFYSTRING is in effect then allocate an extra buffer to hold
+ *       the edited string in some form, either as the string itself or as some
+ *       sort of "edit list" to be applied just before returning.
+ *       Use a buffer that holds the ellipsified current line sans ampersands
+ *       and accept the need occasionally to recalculate the prefixes (if
+ *       DT_EXPANDTABS and not DT_NOPREFIX and not DT_HIDEPREFIX)
+ */
+
+#define TAB     9
+#define LF     10
+#define CR     13
+#define SPACE  32
+#define PREFIX 38
+#define ALPHA_PREFIX 30 /* Win16: Alphabet prefix */
+#define KANA_PREFIX  31 /* Win16: Katakana prefix */
+
+#define FORWARD_SLASH '/'
+#define BACK_SLASH '\\'
+
+static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
+
+typedef struct tag_ellipsis_data
+{
+    int before;
+    int len;
+    int under;
+    int after;
+} ellipsis_data;
+
+/*********************************************************************
+ *                      TEXT_Ellipsify (static)
+ *
+ *  Add an ellipsis to the end of the given string whilst ensuring it fits.
+ *
+ * If the ellipsis alone doesn't fit then it will be returned anyway.
+ *
+ * See Also TEXT_PathEllipsify
+ *
+ * Arguments
+ *   hdc        [in] The handle to the DC that defines the font.
+ *   str        [in/out] The string that needs to be modified.
+ *   max_str    [in] The dimension of str (number of WCHAR).
+ *   len_str    [in/out] The number of characters in str
+ *   width      [in] The maximum width permitted (in logical coordinates)
+ *   size       [out] The dimensions of the text
+ *   modstr     [out] The modified form of the string, to be returned to the
+ *                    calling program.  It is assumed that the caller has
+ *                    made sufficient space available so we don't need to
+ *                    know the size of the space.  This pointer may be NULL if
+ *                    the modified string is not required.
+ *   len_before [out] The number of characters before the ellipsis.
+ *   len_ellip  [out] The number of characters in the ellipsis.
+ *
+ * See for example Microsoft article Q249678.
+ *
+ * For now we will simply use three dots rather than worrying about whether
+ * the font contains an explicit ellipsis character.
+ */
+static void TEXT_Ellipsify (HDC hdc, WCHAR *str, unsigned int max_len,
+                            unsigned int *len_str, int width, SIZE *size,
+                            WCHAR *modstr,
+                            int *len_before, int *len_ellip)
+{
+    unsigned int len_ellipsis;
+    unsigned int lo, mid, hi;
+#ifdef _WIN32K_
+    len_ellipsis = wcslen (ELLIPSISW);
+#else
+    len_ellipsis = strlenW (ELLIPSISW);
+#endif
+    if (len_ellipsis > max_len) len_ellipsis = max_len;
+    if (*len_str > max_len - len_ellipsis)
+        *len_str = max_len - len_ellipsis;
+
+    /* First do a quick binary search to get an upper bound for *len_str. */
+    if (*len_str > 0 &&
+#ifdef _WIN32K_
+        GreGetTextExtentExW(hdc, str, *len_str, width, NULL, NULL, size, 0) &&
+#else
+        GetTextExtentExPointW(hdc, str, *len_str, width, NULL, NULL, size) &&
+#endif
+        size->cx > width)
+    {
+        for (lo = 0, hi = *len_str; lo < hi; )
+        {
+            mid = (lo + hi) / 2;
+#ifdef _WIN32K_
+            if (!GreGetTextExtentExW(hdc, str, mid, width, NULL, NULL, size, 0))
+#else
+            if (!GetTextExtentExPointW(hdc, str, mid, width, NULL, NULL, size))
+#endif
+                break;
+            if (size->cx > width)
+                hi = mid;
+            else
+                lo = mid + 1;
+        }
+        *len_str = hi;
+    }
+    /* Now this should take only a couple iterations at most. */
+    for ( ; ; )
+    {
+        memcpy(str + *len_str, ELLIPSISW, len_ellipsis*sizeof(WCHAR));
+#ifdef _WIN32K_
+        if (!GreGetTextExtentExW (hdc, str, *len_str + len_ellipsis, width,
+                                    NULL, NULL, size, 0)) break;
+#else
+        if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
+                                    NULL, NULL, size)) break;
+#endif
+        if (!*len_str || size->cx <= width) break;
+
+        (*len_str)--;
+    }
+    *len_ellip = len_ellipsis;
+    *len_before = *len_str;
+    *len_str += len_ellipsis;
+
+    if (modstr)
+    {
+        memcpy (modstr, str, *len_str * sizeof(WCHAR));
+        modstr[*len_str] = '\0';
+    }
+}
+
+/*********************************************************************
+ *                      TEXT_PathEllipsify (static)
+ *
+ * Add an ellipsis to the provided string in order to make it fit within
+ * the width.  The ellipsis is added as specified for the DT_PATH_ELLIPSIS
+ * flag.
+ *
+ * See Also TEXT_Ellipsify
+ *
+ * Arguments
+ *   hdc        [in] The handle to the DC that defines the font.
+ *   str        [in/out] The string that needs to be modified
+ *   max_str    [in] The dimension of str (number of WCHAR).
+ *   len_str    [in/out] The number of characters in str
+ *   width      [in] The maximum width permitted (in logical coordinates)
+ *   size       [out] The dimensions of the text
+ *   modstr     [out] The modified form of the string, to be returned to the
+ *                    calling program.  It is assumed that the caller has
+ *                    made sufficient space available so we don't need to
+ *                    know the size of the space.  This pointer may be NULL if
+ *                    the modified string is not required.
+ *   pellip     [out] The ellipsification results
+ *
+ * For now we will simply use three dots rather than worrying about whether
+ * the font contains an explicit ellipsis character.
+ *
+ * The following applies, I think to Win95.  We will need to extend it for
+ * Win98 which can have both path and end ellipsis at the same time (e.g.
+ *  C:\MyLongFileName.Txt becomes ...\MyLongFileN...)
+ *
+ * The resulting string consists of as much as possible of the following:
+ * 1. The ellipsis itself
+ * 2. The last \ or / of the string (if any)
+ * 3. Everything after the last \ or / of the string (if any) or the whole
+ *    string if there is no / or \.  I believe that under Win95 this would
+ *    include everything even though some might be clipped off the end whereas
+ *    under Win98 that might be ellipsified too.
+ *    Yet to be investigated is whether this would include wordbreaking if the
+ *    filename is more than 1 word and splitting if DT_EDITCONTROL was in
+ *    effect.  (If DT_EDITCONTROL is in effect then on occasions text will be
+ *    broken within words).
+ * 4. All the stuff before the / or \, which is placed before the ellipsis.
+ */
+static void TEXT_PathEllipsify (HDC hdc, WCHAR *str, unsigned int max_len,
+                                unsigned int *len_str, int width, SIZE *size,
+                                WCHAR *modstr, ellipsis_data *pellip)
+{
+    int len_ellipsis;
+    int len_trailing;
+    int len_under;
+    WCHAR *lastBkSlash, *lastFwdSlash, *lastSlash;
+#ifdef _WIN32K_
+    len_ellipsis = wcslen (ELLIPSISW);
+#else
+    len_ellipsis = strlenW (ELLIPSISW);
+#endif
+    if (!max_len) return;
+    if (len_ellipsis >= max_len) len_ellipsis = max_len - 1;
+    if (*len_str + len_ellipsis >= max_len)
+        *len_str = max_len - len_ellipsis-1;
+        /* Hopefully this will never happen, otherwise it would probably lose
+         * the wrong character
+         */
+    str[*len_str] = '\0'; /* to simplify things */
+#ifdef _WIN32K_
+    lastBkSlash  = wcsrchr (str, BACK_SLASH);
+    lastFwdSlash = wcsrchr (str, FORWARD_SLASH);
+#else
+    lastBkSlash  = strrchrW (str, BACK_SLASH);
+    lastFwdSlash = strrchrW (str, FORWARD_SLASH);
+#endif
+    lastSlash = lastBkSlash > lastFwdSlash ? lastBkSlash : lastFwdSlash;
+    if (!lastSlash) lastSlash = str;
+    len_trailing = *len_str - (lastSlash - str);
+
+    /* overlap-safe movement to the right */
+    memmove (lastSlash+len_ellipsis, lastSlash, len_trailing * sizeof(WCHAR));
+    memcpy (lastSlash, ELLIPSISW, len_ellipsis*sizeof(WCHAR));
+    len_trailing += len_ellipsis;
+    /* From this point on lastSlash actually points to the ellipsis in front
+     * of the last slash and len_trailing includes the ellipsis
+     */
+
+    len_under = 0;
+    for ( ; ; )
+    {
+#ifdef _WIN32K_
+        if (!GreGetTextExtentExW (hdc, str, *len_str + len_ellipsis, width,
+                                    NULL, NULL, size, 0)) break;
+#else
+        if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
+                                    NULL, NULL, size)) break;
+#endif
+        if (lastSlash == str || size->cx <= width) break;
+
+        /* overlap-safe movement to the left */
+        memmove (lastSlash-1, lastSlash, len_trailing * sizeof(WCHAR));
+        lastSlash--;
+        len_under++;
+
+        assert (*len_str);
+        (*len_str)--;
+    }
+    pellip->before = lastSlash-str;
+    pellip->len = len_ellipsis;
+    pellip->under = len_under;
+    pellip->after = len_trailing - len_ellipsis;
+    *len_str += len_ellipsis;
+
+    if (modstr)
+    {
+        memcpy(modstr, str, *len_str * sizeof(WCHAR));
+        modstr[*len_str] = '\0';
+    }
+}
+
+/* Check the character is Chinese, Japanese, Korean and/or Thai */
+inline BOOL IsCJKT(WCHAR wch)
+{
+    if (0x0E00 <= wch && wch <= 0x0E7F)
+        return TRUE;    /* Thai */
+
+    if (0x3000 <= wch && wch <= 0x9FFF)
+        return TRUE;    /* CJK */
+
+    if (0xAC00 <= wch && wch <= 0xD7FF)
+        return TRUE;    /* Korean */
+
+    if (0xFF00 <= wch && wch <= 0xFFEF)
+        return TRUE;    /* CJK */
+
+    return FALSE;
+}
+
+/* See http://en.wikipedia.org/wiki/Kinsoku_shori */
+static const WCHAR KinsokuClassA[] =
+{
+    0x2010, 0x2013, 0x2019, 0x201D, 0x203C, 0x2047, 0x2048, 0x2049, 0x3001, 
+    0x3002, 0x3005, 0x3009, 0x300B, 0x300D, 0x300F, 0x3011, 0x3015, 0x3017, 
+    0x3019, 0x301C, 0x301F, 0x303B, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049, 
+    0x3063, 0x3083, 0x3085, 0x3087, 0x308E, 0x3095, 0x3096, 0x30A0, 0x30A1, 
+    0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30C3, 0x30E3, 0x30E5, 0x30E7, 0x30EE, 
+    0x30F5, 0x30F6, 0x30FB, 0x30FC, 0x30FD, 0x30FE, 0x31F0, 0x31F1, 0x31F2, 
+    0x31F3, 0x31F4, 0x31F5, 0x31F6, 0x31F7, 0x31F8, 0x31F9, 0x31FA, 0x31FB, 
+    0x31FC, 0x31FD, 0x31FE, 0x31FF, 0xFF01, 0xFF09, 0xFF0C, 0xFF0E, 0xFF1A, 
+    0xFF1B, 0xFF1F, 0xFF3D, 0xFF5D, 0xFF60, 0
+};
+
+/*********************************************************************
+ *                      TEXT_WordBreak (static)
+ *
+ *  Perform wordbreak processing on the given string
+ *
+ * Assumes that DT_WORDBREAK has been specified and not all the characters
+ * fit.  Note that this function should even be called when the first character
+ * that doesn't fit is known to be a space or tab, so that it can swallow them.
+ *
+ * Note that the Windows processing has some strange properties.
+ * 1. If the text is left-justified and there is room for some of the spaces
+ *    that follow the last word on the line then those that fit are included on
+ *    the line.
+ * 2. If the text is centred or right-justified and there is room for some of
+ *    the spaces that follow the last word on the line then all but one of those
+ *    that fit are included on the line.
+ * 3. (Reasonable behaviour) If the word breaking causes a space to be the first
+ *    character of a new line it will be skipped.
+ *
+ * Arguments
+ *   hdc        [in] The handle to the DC that defines the font.
+ *   str        [in/out] The string that needs to be broken.
+ *   max_str    [in] The dimension of str (number of WCHAR).
+ *   len_str    [in/out] The number of characters in str
+ *   width      [in] The maximum width permitted
+ *   format     [in] The format flags in effect
+ *   chars_fit  [in] The maximum number of characters of str that are already
+ *              known to fit; chars_fit+1 is known not to fit.
+ *   chars_used [out] The number of characters of str that have been "used" and
+ *              do not need to be included in later text.  For example this will
+ *              include any spaces that have been discarded from the start of
+ *              the next line.
+ *   size       [out] The size of the returned text in logical coordinates
+ *
+ * Pedantic assumption - Assumes that the text length is monotonically
+ * increasing with number of characters (i.e. no weird kernings)
+ *
+ * Algorithm
+ *
+ * Work back from the last character that did fit to either a space or the last
+ * character of a word, whichever is met first.
+ * If there was one or the first character didn't fit then
+ *     If the text is centred or right justified and that one character was a
+ *     space then break the line before that character
+ *     Otherwise break the line after that character
+ *     and if the next character is a space then discard it.
+ * Suppose there was none (and the first character did fit).
+ *     If Break Within Word is permitted
+ *         break the word after the last character that fits (there must be
+ *         at least one; none is caught earlier).
+ *     Otherwise
+ *         discard any trailing space.
+ *         include the whole word; it may be ellipsified later
+ *
+ * Break Within Word is permitted under a set of circumstances that are not
+ * totally clear yet.  Currently our best guess is:
+ *     If DT_EDITCONTROL is in effect and neither DT_WORD_ELLIPSIS nor
+ *     DT_PATH_ELLIPSIS is
+ */
+
+static void TEXT_WordBreak (HDC hdc, WCHAR *str, unsigned int max_str,
+                            unsigned int *len_str,
+                            int width, int format, unsigned int chars_fit,
+                            unsigned int *chars_used, SIZE *size)
+{
+    WCHAR *p;
+    int word_fits;
+    assert (format & DT_WORDBREAK);
+    assert (chars_fit < *len_str);
+
+    /* Work back from the last character that did fit to either a space or the
+     * last character of a word, whichever is met first.
+     */
+    p = str + chars_fit; /* The character that doesn't fit */
+    word_fits = TRUE;
+    if (!chars_fit)
+        word_fits = FALSE;
+    else if (*p == SPACE) /* chars_fit < *len_str so this is valid */
+        p--; /* the word just fitted */
+    else
+    {
+        while (p > str && *(--p) != SPACE && (!IsCJKT(p[1]) || 
+                p[1] == L'\0' || wcschr(KinsokuClassA, p[1]) != NULL))
+            ;
+        word_fits = (p != str || *p == SPACE || IsCJKT(p[1]));
+    }
+    /* If there was one. */
+    if (word_fits)
+    {
+        int next_is_space;
+        /* break the line before/after that character */
+        if (!(format & (DT_RIGHT | DT_CENTER)) || *p != SPACE)
+            p++;
+        next_is_space = (unsigned int) (p - str) < *len_str && *p == SPACE;
+        *len_str = p - str;
+        /* and if the next character is a space then discard it. */
+        *chars_used = *len_str;
+        if (next_is_space)
+            (*chars_used)++;
+    }
+    /* Suppose there was none. */
+    else
+    {
+        if ((format & (DT_EDITCONTROL | DT_WORD_ELLIPSIS | DT_PATH_ELLIPSIS)) ==
+            DT_EDITCONTROL)
+        {
+            /* break the word after the last character that fits (there must be
+             * at least one). */
+            if (!chars_fit)
+                ++chars_fit;
+            *len_str = chars_fit;
+            *chars_used = chars_fit;
+
+            /* FIXME - possible error.  Since the next character is now removed
+             * this could make the text longer so that it no longer fits, and
+             * so we need a loop to test and shrink.
+             */
+        }
+        /* Otherwise */
+        else
+        {
+            /* discard any trailing space. */
+            const WCHAR *e = str + *len_str;
+            p = str + chars_fit;
+            while (p < e && *p != SPACE)
+                p++;
+            *chars_used = p - str;
+            if (p < e) /* i.e. loop failed because *p == SPACE */
+                (*chars_used)++;
+
+            /* include the whole word; it may be ellipsified later */
+            *len_str = p - str;
+            /* Possible optimisation; if DT_WORD_ELLIPSIS only use chars_fit+1
+             * so that it will be too long
+             */
+        }
+    }
+    /* Remeasure the string */
+#ifdef _WIN32K_
+    GreGetTextExtentExW (hdc, str, *len_str, 0, NULL, NULL, size, 0);
+#else
+    GetTextExtentExPointW (hdc, str, *len_str, 0, NULL, NULL, size);
+#endif
+}
+
+/*********************************************************************
+ *                      TEXT_SkipChars
+ *
+ *  Skip over the given number of characters, bearing in mind prefix
+ *  substitution and the fact that a character may take more than one
+ *  WCHAR (Unicode surrogates are two words long) (and there may have been
+ *  a trailing &)
+ *
+ * Parameters
+ *   new_count  [out] The updated count
+ *   new_str    [out] The updated pointer
+ *   start_count [in] The count of remaining characters corresponding to the
+ *                    start of the string
+ *   start_str  [in] The starting point of the string
+ *   max        [in] The number of characters actually in this segment of the
+ *                   string (the & counts)
+ *   n          [in] The number of characters to skip (if prefix then
+ *                   &c counts as one)
+ *   prefix     [in] Apply prefix substitution
+ *
+ * Return Values
+ *   none
+ *
+ * Remarks
+ *   There must be at least n characters in the string
+ *   We need max because the "line" may have ended with a & followed by a tab
+ *   or newline etc. which we don't want to swallow
+ */
+
+static void TEXT_SkipChars (int *new_count, const WCHAR **new_str,
+                            int start_count, const WCHAR *start_str,
+                            int max, int n, int prefix)
+{
+    /* This is specific to wide characters, MSDN doesn't say anything much
+     * about Unicode surrogates yet and it isn't clear if _wcsinc will
+     * correctly handle them so we'll just do this the easy way for now
+     */
+
+    if (prefix)
+    {
+        const WCHAR *str_on_entry = start_str;
+        assert (max >= n);
+        max -= n;
+        while (n--)
+        {
+            if ((*start_str == PREFIX || *start_str == ALPHA_PREFIX) && max--)
+                start_str++;
+            start_str++;
+        }
+        start_count -= (start_str - str_on_entry);
+    }
+    else
+    {
+        start_str += n;
+        start_count -= n;
+    }
+    *new_str = start_str;
+    *new_count = start_count;
+}
+
+/*********************************************************************
+ *                      TEXT_Reprefix
+ *
+ *  Reanalyse the text to find the prefixed character.  This is called when
+ *  wordbreaking or ellipsification has shortened the string such that the
+ *  previously noted prefixed character is no longer visible.
+ *
+ * Parameters
+ *   str        [in] The original string segment (including all characters)
+ *   ns         [in] The number of characters in str (including prefixes)
+ *   pe         [in] The ellipsification data
+ *
+ * Return Values
+ *   The prefix offset within the new string segment (the one that contains the
+ *   ellipses and does not contain the prefix characters) (-1 if none)
+ */
+
+static int TEXT_Reprefix (const WCHAR *str, unsigned int ns,
+                          const ellipsis_data *pe)
+{
+    int result = -1;
+    unsigned int i;
+    unsigned int n = pe->before + pe->under + pe->after;
+    assert (n <= ns);
+    for (i = 0; i < n; i++, str++)
+    {
+        if (i == (unsigned int) pe->before)
+        {
+            /* Reached the path ellipsis; jump over it */
+            if (ns < (unsigned int) pe->under) break;
+            str += pe->under;
+            ns -= pe->under;
+            i += pe->under;
+            if (!pe->after) break; /* Nothing after the path ellipsis */
+        }
+        if (!ns) break;
+        ns--;
+        if (*str++ == PREFIX || *str == ALPHA_PREFIX)
+        {
+            str++;
+            if (!ns) break;
+            if (*str != PREFIX)
+                result = (i < (unsigned int) pe->before || pe->under == 0) ? i : i - pe->under + pe->len;
+                /* pe->len may be non-zero while pe_under is zero */
+            ns--;
+        }
+    }
+    return result;
+}
+
+/*********************************************************************
+ *  Returns true if and only if the remainder of the line is a single
+ *  newline representation or nothing
+ */
+
+static int remainder_is_none_or_newline (int num_chars, const WCHAR *str)
+{
+    if (!num_chars) return TRUE;
+    if (*str != LF && *str != CR) return FALSE;
+    if (!--num_chars) return TRUE;
+    if (*str == *(str+1)) return FALSE;
+    str++;
+    if (*str != CR && *str != LF) return FALSE;
+    if (--num_chars) return FALSE;
+    return TRUE;
+}
+
+/*********************************************************************
+ *  Return next line of text from a string.
+ *
+ * hdc - handle to DC.
+ * str - string to parse into lines.
+ * count - length of str.
+ * dest - destination in which to return line.
+ * len - dest buffer size in chars on input, copied length into dest on output.
+ * width - maximum width of line in pixels.
+ * format - format type passed to DrawText.
+ * retsize - returned size of the line in pixels.
+ * last_line - TRUE if is the last line that will be processed
+ * p_retstr - If DT_MODIFYSTRING this points to a cursor in the buffer in which
+ *            the return string is built.
+ * tabwidth - The width of a tab in logical coordinates
+ * pprefix_offset - Here is where we return the offset within dest of the first
+ *                  prefixed (underlined) character.  -1 is returned if there
+ *                  are none.  Note that there may be more; the calling code
+ *                  will need to use TEXT_Reprefix to find any later ones.
+ * pellip - Here is where we return the information about any ellipsification
+ *          that was carried out.  Note that if tabs are being expanded then
+ *          this data will correspond to the last text segment actually
+ *          returned in dest; by definition there would not have been any
+ *          ellipsification in earlier text segments of the line.
+ *
+ * Returns pointer to next char in str after end of the line
+ * or NULL if end of str reached.
+ */
+static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count,
+                                 WCHAR *dest, int *len, int width, DWORD format,
+                                 SIZE *retsize, int last_line, WCHAR **p_retstr,
+                                 int tabwidth, int *pprefix_offset,
+                                 ellipsis_data *pellip)
+{
+    int i = 0, j = 0;
+    int plen = 0;
+    SIZE size = {0, 0};
+    int maxl = *len;
+    int seg_i, seg_count, seg_j;
+    int max_seg_width;
+    int num_fit;
+    int word_broken;
+    int line_fits;
+    unsigned int j_in_seg;
+    int ellipsified;
+    *pprefix_offset = -1;
+
+    /* For each text segment in the line */
+
+    retsize->cy = 0;
+    while (*count)
+    {
+
+        /* Skip any leading tabs */
+
+        if (str[i] == TAB && (format & DT_EXPANDTABS))
+        {
+            plen = ((plen/tabwidth)+1)*tabwidth;
+            (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
+            while (*count && str[i] == TAB)
+            {
+                plen += tabwidth;
+                (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
+            }
+        }
+
+
+        /* Now copy as far as the next tab or cr/lf or eos */
+
+        seg_i = i;
+        seg_count = *count;
+        seg_j = j;
+
+        while (*count &&
+               (str[i] != TAB || !(format & DT_EXPANDTABS)) &&
+               ((str[i] != CR && str[i] != LF) || (format & DT_SINGLELINE)))
+        {
+            if ((format & DT_NOPREFIX) || *count <= 1)
+            {
+                (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
+                continue;
+            }
+
+           if (str[i] == PREFIX || str[i] == ALPHA_PREFIX) {
+                (*count)--, i++; /* Throw away the prefix itself */
+                if (str[i] == PREFIX)
+                {
+                    /* Swallow it before we see it again */
+                   (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
+                }
+               else if (*pprefix_offset == -1 || *pprefix_offset >= seg_j)
+                {
+                    *pprefix_offset = j;
+                }
+                /* else the previous prefix was in an earlier segment of the
+                 * line; we will leave it to the drawing code to catch this
+                 * one.
+                 */
+           }
+           else if (str[i] == KANA_PREFIX)
+            {
+                /* Throw away katakana access keys */
+                (*count)--, i++; /* skip the prefix */
+                (*count)--, i++; /* skip the letter */
+            }
+            else
+            {
+                (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
+            }
+        }
+
+
+        /* Measure the whole text segment and possibly WordBreak and
+         * ellipsify it
+         */
+
+        j_in_seg = j - seg_j;
+        max_seg_width = width - plen;
+#ifdef _WIN32K_
+        GreGetTextExtentExW (hdc, dest + seg_j, j_in_seg, max_seg_width, (PULONG)&num_fit, NULL, &size, 0);
+#else
+        GetTextExtentExPointW (hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size);
+#endif
+
+        /* The Microsoft handling of various combinations of formats is weird.
+         * The following may very easily be incorrect if several formats are
+         * combined, and may differ between versions (to say nothing of the
+         * several bugs in the Microsoft versions).
+         */
+        word_broken = 0;
+        line_fits = (num_fit >= j_in_seg);
+        if (!line_fits && (format & DT_WORDBREAK))
+        {
+            const WCHAR *s;
+            unsigned int chars_used;
+            TEXT_WordBreak (hdc, dest+seg_j, maxl-seg_j, &j_in_seg,
+                            max_seg_width, format, num_fit, &chars_used, &size);
+            line_fits = (size.cx <= max_seg_width);
+            /* and correct the counts */
+            TEXT_SkipChars (count, &s, seg_count, str+seg_i, i-seg_i,
+                            chars_used, !(format & DT_NOPREFIX));
+            i = s - str;
+            word_broken = 1;
+        }
+        pellip->before = j_in_seg;
+        pellip->under = 0;
+        pellip->after = 0;
+        pellip->len = 0;
+        ellipsified = 0;
+        if (!line_fits && (format & DT_PATH_ELLIPSIS))
+        {
+            TEXT_PathEllipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg,
+                                max_seg_width, &size, *p_retstr, pellip);
+            line_fits = (size.cx <= max_seg_width);
+            ellipsified = 1;
+        }
+        /* NB we may end up ellipsifying a word-broken or path_ellipsified
+         * string */
+        if ((!line_fits && (format & DT_WORD_ELLIPSIS)) ||
+            ((format & DT_END_ELLIPSIS) &&
+              ((last_line && *count) ||
+               (remainder_is_none_or_newline (*count, &str[i]) && !line_fits))))
+        {
+            int before, len_ellipsis;
+            TEXT_Ellipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg,
+                            max_seg_width, &size, *p_retstr, &before, &len_ellipsis);
+            if (before > pellip->before)
+            {
+                /* We must have done a path ellipsis too */
+                pellip->after = before - pellip->before - pellip->len;
+                /* Leave the len as the length of the first ellipsis */
+            }
+            else
+            {
+                /* If we are here after a path ellipsification it must be
+                 * because even the ellipsis itself didn't fit.
+                 */
+                assert (pellip->under == 0 && pellip->after == 0);
+                pellip->before = before;
+                pellip->len = len_ellipsis;
+                /* pellip->after remains as zero as does
+                 * pellip->under
+                 */
+            }
+            line_fits = (size.cx <= max_seg_width);
+            ellipsified = 1;
+        }
+        /* As an optimisation if we have ellipsified and we are expanding
+         * tabs and we haven't reached the end of the line we can skip to it
+         * now rather than going around the loop again.
+         */
+        if ((format & DT_EXPANDTABS) && ellipsified)
+        {
+            if (format & DT_SINGLELINE)
+                *count = 0;
+            else
+            {
+                while ((*count) && str[i] != CR && str[i] != LF)
+                {
+                    (*count)--, i++;
+                }
+            }
+        }
+
+        j = seg_j + j_in_seg;
+        if (*pprefix_offset >= seg_j + pellip->before)
+        {
+            *pprefix_offset = TEXT_Reprefix (str + seg_i, i - seg_i, pellip);
+            if (*pprefix_offset != -1)
+                *pprefix_offset += seg_j;
+        }
+
+        plen += size.cx;
+        if (size.cy > retsize->cy)
+            retsize->cy = size.cy;
+
+        if (word_broken)
+            break;
+        else if (!*count)
+            break;
+        else if (str[i] == CR || str[i] == LF)
+        {
+            (*count)--, i++;
+            if (*count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1])
+            {
+                (*count)--, i++;
+            }
+            break;
+        }
+        /* else it was a Tab and we go around again */
+    }
+
+    retsize->cx = plen;
+    *len = j;
+    if (*count)
+        return (&str[i]);
+    else
+        return NULL;
+}
+
+
+/***********************************************************************
+ *                      TEXT_DrawUnderscore
+ *
+ *  Draw the underline under the prefixed character
+ *
+ * Parameters
+ *   hdc        [in] The handle of the DC for drawing
+ *   x          [in] The x location of the line segment (logical coordinates)
+ *   y          [in] The y location of where the underscore should appear
+ *                   (logical coordinates)
+ *   str        [in] The text of the line segment
+ *   offset     [in] The offset of the underscored character within str
+ *   rect       [in] Clipping rectangle (if not NULL)
+ */
+/* Synced with wine 1.1.32 */
+static void TEXT_DrawUnderscore (HDC hdc, int x, int y, const WCHAR *str, int offset, const RECT *rect)
+{
+    int prefix_x;
+    int prefix_end;
+    SIZE size;
+    HPEN hpen;
+    HPEN oldPen;
+#ifdef _WIN32K_
+    GreGetTextExtentW (hdc, (LPWSTR)str, offset, &size, 1);
+#else
+    GetTextExtentPointW (hdc, str, offset, &size);
+#endif
+    prefix_x = x + size.cx;
+#ifdef _WIN32K_
+    GreGetTextExtentW (hdc, (LPWSTR)str, offset+1, &size, 1);
+#else
+    GetTextExtentPointW (hdc, str, offset+1, &size);
+#endif
+    prefix_end = x + size.cx - 1;
+    /* The above method may eventually be slightly wrong due to kerning etc. */
+
+    /* Check for clipping */
+    if (rect)
+    {
+        if (prefix_x > rect->right || prefix_end < rect->left ||
+            y < rect->top || y > rect->bottom)
+            return; /* Completely outside */
+        /* Partially outside */
+        if (prefix_x   < rect->left ) prefix_x   = rect->left;
+        if (prefix_end > rect->right) prefix_end = rect->right;
+    }
+#ifdef _WIN32K_
+    hpen = NtGdiCreatePen (PS_SOLID, 1, GreGetTextColor (hdc), NULL);
+    oldPen = NtGdiSelectPen (hdc, hpen);
+    GreMoveTo (hdc, prefix_x, y, NULL);
+    NtGdiLineTo (hdc, prefix_end, y);
+    NtGdiSelectPen (hdc, oldPen);
+    GreDeleteObject (hpen);
+#else
+    hpen = CreatePen (PS_SOLID, 1, GetTextColor (hdc));
+    oldPen = SelectObject (hdc, hpen);
+    MoveToEx (hdc, prefix_x, y, NULL);
+    LineTo (hdc, prefix_end, y);
+    SelectObject (hdc, oldPen);
+    DeleteObject (hpen);
+#endif
+}
+
+/***********************************************************************
+ *           DrawTextExW    (USER32.@)
+ *
+ * The documentation on the extra space required for DT_MODIFYSTRING at MSDN
+ * is not quite complete, especially with regard to \0.  We will assume that
+ * the returned string could have a length of up to i_count+3 and also have
+ * a trailing \0 (which would be 4 more than a not-null-terminated string but
+ * 3 more than a null-terminated string).  If this is not so then increase
+ * the allowance in DrawTextExA.
+ */
+#define MAX_BUFFER 1024
+/* 
+ * DrawTextExW
+ *
+ * Synced with Wine Staging 1.7.37
+ */
+INT WINAPI DrawTextExWorker( HDC hdc,
+                             LPWSTR str,
+                             INT i_count,
+                             LPRECT rect,
+                             UINT flags,
+                             LPDRAWTEXTPARAMS dtp )
+{
+    SIZE size;
+    const WCHAR *strPtr;
+    WCHAR *retstr, *p_retstr;
+    size_t size_retstr;
+    WCHAR line[MAX_BUFFER];
+    int len, lh, count=i_count;
+    TEXTMETRICW tm;
+    int lmargin = 0, rmargin = 0;
+    int x = rect->left, y = rect->top;
+    int width = rect->right - rect->left;
+    int max_width = 0;
+    int last_line;
+    int tabwidth /* to keep gcc happy */ = 0;
+    int prefix_offset;
+    ellipsis_data ellip;
+    BOOL invert_y=FALSE;
+#ifdef _WIN32K_
+    TRACE("%S, %d, %08x\n", str, count, flags);
+#else
+    TRACE("%s, %d, [%s] %08x\n", debugstr_wn (str, count), count,
+        wine_dbgstr_rect(rect), flags);
+#endif
+    if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
+          dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin);
+
+    if (!str) return 0;
+
+    strPtr = str;
+
+    if (flags & DT_SINGLELINE)
+        flags &= ~DT_WORDBREAK;
+#ifdef _WIN32K_
+    GreGetTextMetricsW(hdc, &tm);
+#else
+    GetTextMetricsW(hdc, &tm);
+#endif
+    if (flags & DT_EXTERNALLEADING)
+       lh = tm.tmHeight + tm.tmExternalLeading;
+    else
+       lh = tm.tmHeight;
+
+    if (str[0] && count == 0)
+        return lh;
+
+    if (dtp && dtp->cbSize != sizeof(DRAWTEXTPARAMS))
+        return 0;
+#ifdef _WIN32K_
+    if (GreGetGraphicsMode(hdc) == GM_COMPATIBLE)
+    {
+        SIZE window_ext, viewport_ext;
+        GreGetWindowExtEx(hdc, &window_ext);
+        GreGetViewportExtEx(hdc, &viewport_ext);
+        if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
+            invert_y = TRUE;
+    }
+#else
+    if (GetGraphicsMode(hdc) == GM_COMPATIBLE)
+    {
+        SIZE window_ext, viewport_ext;
+        GetWindowExtEx(hdc, &window_ext);
+        GetViewportExtEx(hdc, &viewport_ext);
+        if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
+            invert_y = TRUE;
+    }
+#endif
+    if (count == -1)
+    {
+#ifdef _WIN32K_
+        count = wcslen(str);
+#else
+        count = strlenW(str);
+#endif
+        if (count == 0)
+        {
+            if( flags & DT_CALCRECT)
+            {
+                rect->right = rect->left;
+                if( flags & DT_SINGLELINE)
+                    rect->bottom = rect->top + (invert_y ? -lh : lh);
+                else
+                    rect->bottom = rect->top;
+            }
+            return lh;
+        }
+    }
+
+    if (dtp)
+    {
+        lmargin = dtp->iLeftMargin;
+        rmargin = dtp->iRightMargin;
+        if (!(flags & (DT_CENTER | DT_RIGHT)))
+            x += lmargin;
+        dtp->uiLengthDrawn = 0;     /* This param RECEIVES number of chars processed */
+    }
+
+    if (flags & DT_EXPANDTABS)
+    {
+        int tabstop = ((flags & DT_TABSTOP) && dtp) ? dtp->iTabLength : 8;
+       tabwidth = tm.tmAveCharWidth * tabstop;
+    }
+
+    if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
+
+    if (flags & DT_MODIFYSTRING)
+    {
+        size_retstr = (count + 4) * sizeof (WCHAR);
+#ifdef _WIN32K_
+        retstr = ExAllocatePoolWithTag(PagedPool, size_retstr, USERTAG_RTL);
+#else
+        retstr = HeapAlloc(GetProcessHeap(), 0, size_retstr);
+#endif
+        if (!retstr) return 0;
+        memcpy (retstr, str, size_retstr);
+    }
+    else
+    {
+        size_retstr = 0;
+        retstr = NULL;
+    }
+    p_retstr = retstr;
+
+    do
+    {
+       len = sizeof(line)/sizeof(line[0]);
+       if (invert_y)
+            last_line = !(flags & DT_NOCLIP) && y - ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) < rect->bottom;
+       else
+            last_line = !(flags & DT_NOCLIP) && y + ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) > rect->bottom;
+       strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, &p_retstr, tabwidth, &prefix_offset, &ellip);
+
+#ifdef __REACTOS__
+    if (flags & DT_CENTER)
+    {
+        if (((rect->right - rect->left) < size.cx) && (flags & DT_CALCRECT))
+        {
+            x = rect->left + size.cx;
+        }
+        else
+        {
+            x = (rect->left + rect->right - size.cx)