[CMAKE]
[reactos.git] / dll / win32 / user32 / windows / menu.c
index 58c4a95..34eaac9 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS user32.dll
  * FILE:            user32/windows/menu.c
@@ -34,7 +33,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(menu);
 
 /* Internal MenuTrackMenu() flags */
 #define TPM_INTERNAL           0xF0000000
-#define TPM_ENTERIDLEEX                0x80000000              /* set owner window for WM_ENTERIDLE */
 #define TPM_BUTTONDOWN         0x40000000              /* menu was clicked before tracking */
 #define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
 
@@ -58,6 +56,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(menu);
 /* Use global popup window because there's no way 2 menus can
  * be tracked at the same time.  */
 static HWND top_popup;
+static HMENU top_popup_hmenu;
 
 /* Flag set by EndMenu() to force an exit from menu tracking */
 static BOOL fEndMenu = FALSE;
@@ -67,11 +66,6 @@ static BOOL fEndMenu = FALSE;
 #define SEPARATOR_HEIGHT (5)
 #define MENU_TAB_SPACE (8)
 
-#define MAKEINTATOMA(atom)  ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
-#define MAKEINTATOMW(atom)  ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
-#define POPUPMENU_CLASS_ATOMA   MAKEINTATOMA(32768)  /* PopupMenu */
-#define POPUPMENU_CLASS_ATOMW   MAKEINTATOMW(32768)  /* PopupMenu */
-
 typedef struct
 {
   UINT  TrackFlags;
@@ -87,7 +81,7 @@ typedef struct
  */
 const struct builtin_class_descr POPUPMENU_builtin_class =
 {
-    POPUPMENU_CLASS_ATOMW,                     /* name */
+    WC_MENU,                     /* name */
     CS_SAVEBITS | CS_DBLCLKS,                  /* style  */
     (WNDPROC) NULL,                            /* FIXME - procA */
     (WNDPROC) PopupMenuWndProcW,               /* FIXME - procW */
@@ -517,57 +511,46 @@ static UINT FASTCALL MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo,
   TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo);
 
   if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self))
-    {
+  {
       if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE)))
-        {
+      {
           MenuInfo = &SysMenuInfo;
-        }
+      }
       else
-        {
+      {
           MenuInfo = NULL;
-        }
-    }
+      }
+  }
 
   if (NULL != MenuInfo)
-    {
+  {
       if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0)
-        {
+      {
           return -1;
-        }
-      if (! ForceMenuChar)
-        {
-          Key = toupperW(Key);
+      }
+      if ( !ForceMenuChar )
+      {
           ItemInfo = Items;
           for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++)
-            {
-              if ((ItemInfo->Text) && NULL != ItemInfo->dwTypeData)
-                {
+          {
+              if ((ItemInfo->lpstr) && NULL != ItemInfo->dwTypeData)
+              {
                   WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2;
                   do
-                    {
-                      p = strchrW(p + 2, '&');
-                   }
-                  while (NULL != p && L'&' == p[1]);
-                  if (NULL != p && (toupperW(p[1]) == Key))
-                    {
-                      return i;
-                    }
-                }
-            }
-        }
+                  {
+                      p = strchrW (p + 2, '&');
+                  }
+                  while (p != NULL && p [1] == '&');
+                  if (p && (toupperW(p[1]) == toupperW(Key))) return i;
+              }
+          }
+      }
 
       MenuChar = SendMessageW(WndOwner, WM_MENUCHAR,
                               MAKEWPARAM(Key, MenuInfo->Flags), (LPARAM) MenuInfo->Self);
-      if (2 == HIWORD(MenuChar))
-        {
-          return LOWORD(MenuChar);
-        }
-      if (1 == HIWORD(MenuChar))
-        {
-          return (UINT) (-2);
-        }
+      if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
+      if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
     }
-
   return (UINT)(-1);
 }
 
@@ -576,8 +559,7 @@ static UINT FASTCALL MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo,
  *
  * Get the size of a bitmap item.
  */
-static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size,
-                                                                                  HWND WndOwner)
+static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, HWND WndOwner)
 {
     BITMAP bm;
     HBITMAP bmp = lpitem->hbmpItem;
@@ -784,7 +766,7 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN
         mis.itemWidth  = 0;
         SendMessageW( hwndOwner, 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. 
+         * width of a menufont character to the width of an owner-drawn menu.
          */
         lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
 
@@ -808,7 +790,7 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN
         return;
     }
 
-    lpitem->XTab = 0;
+    lpitem->dxTab = 0;
 
     if (lpitem->hbmpItem)
     {
@@ -831,12 +813,12 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN
             if( !(MenuInfo->dwStyle & MNS_NOCHECK))
                 lpitem->Rect.right += 2 * check_bitmap_width;
             lpitem->Rect.right += 4 + MenuCharSize.cx;
-            lpitem->XTab = lpitem->Rect.right;
+            lpitem->dxTab = lpitem->Rect.right;
             lpitem->Rect.right += check_bitmap_width;
         } else /* hbmpItem & MenuBar */ {
             MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
             lpitem->Rect.right  += size.cx;
-            if( lpitem->Text) lpitem->Rect.right  += 2;
+            if( lpitem->lpstr) lpitem->Rect.right  += 2;
             itemheight = size.cy;
 
             /* Special case: Minimize button doesn't have a space behind it. */
@@ -849,12 +831,12 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN
         if( !(MenuInfo->dwStyle & MNS_NOCHECK))
              lpitem->Rect.right += check_bitmap_width;
         lpitem->Rect.right += 4 + MenuCharSize.cx;
-        lpitem->XTab = lpitem->Rect.right;
+        lpitem->dxTab = lpitem->Rect.right;
         lpitem->Rect.right += check_bitmap_width;
     }
 
     /* it must be a text item - unless it's the system menu */
-    if (!(lpitem->fType & MF_SYSMENU) && lpitem->Text) {
+    if (!(lpitem->fType & MF_SYSMENU) && lpitem->lpstr) {
         HFONT hfontOld = NULL;
         RECT rc = lpitem->Rect;
         LONG txtheight, txtwidth;
@@ -864,7 +846,7 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN
         }
         if (menuBar) {
             txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
-                    DT_SINGLELINE|DT_CALCRECT); 
+                    DT_SINGLELINE|DT_CALCRECT);
             lpitem->Rect.right  += rc.right - rc.left;
             itemheight = max( max( itemheight, txtheight),
                     GetSystemMetrics( SM_CYMENU) - 1);
@@ -883,7 +865,7 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN
                 /* get text size after the tab */
                 tmpheight = DrawTextW( hdc, p, -1, &tmprc,
                         DT_SINGLELINE|DT_CALCRECT);
-                lpitem->XTab += txtwidth;
+                lpitem->dxTab += txtwidth;
                 txtheight = max( txtheight, tmpheight);
                 txtwidth += MenuCharSize.cx + /* space for the tab */
                     tmprc.right - tmprc.left; /* space for the short cut */
@@ -891,7 +873,7 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN
                 txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
                         DT_SINGLELINE|DT_CALCRECT);
                 txtwidth = rc.right - rc.left;
-                lpitem->XTab += txtwidth;
+                lpitem->dxTab += txtwidth;
             }
             lpitem->Rect.right  += 2 + txtwidth;
             itemheight = max( itemheight,
@@ -967,10 +949,10 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
 //        }
           maxX = max(maxX, lpitem.Rect.right);
           orgY = lpitem.Rect.bottom;
-          if ((lpitem.Text) && lpitem.XTab )
+          if ((lpitem.lpstr) && lpitem.dxTab )
              {
-              maxTab = max( maxTab, lpitem.XTab );
-              maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.XTab);
+              maxTab = max( maxTab, lpitem.dxTab );
+              maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab);
           }
         }
 
@@ -981,9 +963,9 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
             if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem))
             {
                 lpitem.Rect.right = maxX;
-                if ((lpitem.Text) && 0 != lpitem.XTab)
+                if ((lpitem.lpstr) && 0 != lpitem.dxTab)
                 {
-                    lpitem.XTab = maxTab;
+                    lpitem.dxTab = maxTab;
                 }
                 MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
             }
@@ -1166,7 +1148,7 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd
 
     SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
     bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
-  
+
     /* Setup colors */
 
     if (lpitem->fState & MF_HILITE)
@@ -1326,7 +1308,7 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd
          * Custom checkmark bitmaps are monochrome but not always 1bpp.
          */
         if( !(MenuInfo->dwStyle & MNS_NOCHECK)) {
-            bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked : 
+            bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
                 lpitem->hbmpUnchecked;
             if (bm)  /* we have a custom bitmap */
             {
@@ -1381,7 +1363,7 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd
     }
 
     /* process text if present */
-    if (lpitem->Text)
+    if (lpitem->lpstr)
     {
         register int i = 0;
         HFONT hfontOld = 0;
@@ -1431,12 +1413,12 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd
         {
             if (L'\t' == Text[i])
             {
-                rect.left = lpitem->XTab;
+                rect.left = lpitem->dxTab;
                 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
             }
             else
             {
-                rect.right = lpitem->XTab;
+                rect.right = lpitem->dxTab;
                 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
             }
 
@@ -1497,7 +1479,7 @@ static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu )
             if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.MenuItemCount)
             {
                 UINT u;
-                
+
                                MenuInitRosMenuItemInfo(&ItemInfo);
 
                 for (u = 0; u < MenuInfo.MenuItemCount; u++)
@@ -1584,6 +1566,11 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl
     }
 
     /* store the owner for DrawItem */
+    if (!IsWindow(hwndOwner))
+    {
+       SetLastError( ERROR_INVALID_WINDOW_HANDLE );
+       return FALSE;
+    }
     MenuInfo.WndOwner = hwndOwner;
     MenuSetRosMenuInfo(&MenuInfo);
 
@@ -1607,36 +1594,39 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl
     if( flags & TPM_BOTTOMALIGN ) y -= height;
     if( flags & TPM_VCENTERALIGN ) y -= height / 2;
 
-    if( x + width > info.rcWork.right)
+    if( x + width > info.rcMonitor.right)
     {
         if( xanchor && x >= width - xanchor )
             x -= width - xanchor;
 
-        if( x + width > info.rcWork.right)
-            x = info.rcWork.right - width;
+        if( x + width > info.rcMonitor.right)
+            x = info.rcMonitor.right - width;
     }
-    if( x < info.rcWork.left ) x = info.rcWork.left;
+    if( x < info.rcMonitor.left ) x = info.rcMonitor.left;
 
-    if( y + height > info.rcWork.bottom)
+    if( y + height > info.rcMonitor.bottom)
     {
         if( yanchor && y >= height + yanchor )
             y -= height + yanchor;
 
-        if( y + height > info.rcWork.bottom)
-            y = info.rcWork.bottom - height;
+        if( y + height > info.rcMonitor.bottom)
+            y = info.rcMonitor.bottom - height;
     }
-    if( y < info.rcWork.top ) y = info.rcWork.top;
+    if( y < info.rcMonitor.top ) y = info.rcMonitor.top;
 
     /* NOTE: In Windows, top menu popup is not owned. */
-    MenuInfo.Wnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL,
+    MenuInfo.Wnd = CreateWindowExW( 0, WC_MENU, NULL,
                                   WS_POPUP, x, y, width, height,
                                   hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
                                  (LPVOID) MenuInfo.Self);
     if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE;
     if (!top_popup) {
         top_popup = MenuInfo.Wnd;
+        top_popup_hmenu = hmenu;
     }
 
+    IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
+
     /* Display the window */
 
     SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0,
@@ -1645,6 +1635,7 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl
     return TRUE;
 }
 
+
 /***********************************************************************
  *           MenuSelectItem
  */
@@ -1663,6 +1654,7 @@ static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIn
     else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW);
     if (!top_popup) {
         top_popup = hmenu->Wnd;
+        top_popup_hmenu = hmenu->Self;
     }
 
     SelectObject( hdc, hMenuFont );
@@ -1794,16 +1786,31 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
   MenuCleanupRosMenuItemInfo(&ItemInfo);
 }
 
+//
+// This breaks some test results. Should handle A2U if called!
+//
 LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
 {
   TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+#ifdef __REACTOS__
+  PWND pWnd;
+
+  pWnd = ValidateHwnd(Wnd);
+  if (pWnd)
+  {
+     if (!pWnd->fnid)
+     {
+        NtUserSetWindowFNID(Wnd, FNID_MENU);
+     }
+  }    
+#endif    
 
   switch(Message)
     {
     case WM_CREATE:
       {
         CREATESTRUCTA *cs = (CREATESTRUCTA *) lParam;
-        SetWindowLongPtrA(Wnd, 0, (LONGcs->lpCreateParams);
+        SetWindowLongPtrA(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
         return 0;
       }
 
@@ -1834,7 +1841,11 @@ LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM l
       if (Wnd == top_popup)
         {
           top_popup = NULL;
+          top_popup_hmenu = NULL;
         }
+#ifdef __REACTOS__
+      NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+#endif
       break;
 
     case WM_SHOWWINDOW:
@@ -1856,7 +1867,7 @@ LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM l
       break;
 
     case MM_GETMENUHANDLE:
-    case MN_GETHMENU: 
+    case MN_GETHMENU:
       return GetWindowLongPtrA(Wnd, 0);
 
     default:
@@ -1869,13 +1880,25 @@ LRESULT WINAPI
 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
 {
   TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+#ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
+  PWND pWnd;
+
+  pWnd = ValidateHwnd(Wnd);
+  if (pWnd)
+  {
+     if (!pWnd->fnid)
+     {
+        NtUserSetWindowFNID(Wnd, FNID_MENU);
+     }
+  }    
+#endif    
 
   switch(Message)
     {
     case WM_CREATE:
       {
         CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
-        SetWindowLongPtrW(Wnd, 0, (LONGcs->lpCreateParams);
+        SetWindowLongPtrW(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
         return 0;
       }
 
@@ -1906,7 +1929,11 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
       if (Wnd == top_popup)
         {
           top_popup = NULL;
+          top_popup_hmenu = NULL;
         }
+#ifdef __REACTOS__
+      NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+#endif
       break;
 
     case WM_SHOWWINDOW:
@@ -2203,8 +2230,8 @@ DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font)
 
   SelectObject(DC, GetStockObject(DC_PEN));
   SetDCPenColor(DC, GetSysColor(COLOR_3DFACE));
-  MoveToEx(DC, Rect->left, Rect->bottom, NULL);
-  LineTo(DC, Rect->right, Rect->bottom);
+  MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL);
+  LineTo(DC, Rect->right, Rect->bottom - 1);
 
   if (0 == MenuInfo.MenuItemCount)
     {
@@ -2354,13 +2381,30 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl
   return Ret;
 }
 
+/**********************************************************************
+ *         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( HWND hwnd )
+{
+    ROSMENUINFO MenuInfo;
+    BOOL Ret = FALSE;
+    if (top_popup_hmenu)
+       Ret = MenuGetRosMenuInfo(&MenuInfo, top_popup_hmenu);
+    if (Ret && hwnd == MenuInfo.WndOwner) EndMenu();
+}
+
 /***********************************************************************
  *           MenuHideSubPopups
  *
  * Hide the sub-popup menus of this menu.
  */
 static void FASTCALL
-MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SendMenuSelect)
+MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo,
+                               BOOL SendMenuSelect, UINT wFlags)
 {
   ROSMENUINFO SubMenuInfo;
   ROSMENUITEMINFO ItemInfo;
@@ -2368,28 +2412,32 @@ MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SendMenuSelect)
   TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
 
   if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->FocusedItem)
-    {
+  {
       MenuInitRosMenuItemInfo(&ItemInfo);
       ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE;
       if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)
           || 0 == (ItemInfo.fType & MF_POPUP)
           || 0 == (ItemInfo.fState & MF_MOUSESELECT))
-        {
+      {
           MenuCleanupRosMenuItemInfo(&ItemInfo);
           return;
-        }
+      }
       ItemInfo.fState &= ~MF_MOUSESELECT;
       ItemInfo.fMask |= MIIM_STATE;
       MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
       if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
-        {
-          MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE);
+      {
+          MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags);
           MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
           DestroyWindow(SubMenuInfo.Wnd);
           SubMenuInfo.Wnd = NULL;
           MenuSetRosMenuInfo(&SubMenuInfo);
-        }
-    }
+
+          if (!(wFlags & TPM_NONOTIFY))
+             SendMessageW( WndOwner, WM_UNINITMENUPOPUP, (WPARAM)ItemInfo.hSubMenu,
+                                 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo)) );
+      }
+  }
 }
 
 /***********************************************************************
@@ -2398,7 +2446,7 @@ MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SendMenuSelect)
  * Helper function for menu navigation routines.
  */
 static void FASTCALL
-MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index)
+MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlags)
 {
   ROSMENUINFO TopMenuInfo;
 
@@ -2409,13 +2457,13 @@ MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index)
       0 == ((PtMenuInfo->Flags | TopMenuInfo.Flags) & MF_POPUP))
     {
       /* both are top level menus (system and menu-bar) */
-      MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE);
+      MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
       MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
       Mt->TopMenu = PtMenuInfo->Self;
     }
   else
     {
-      MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE);
+      MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE, wFlags);
     }
 
   MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
@@ -2531,7 +2579,7 @@ MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
        {
           if (MenuInfo.FocusedItem != Index)
             {
-              MenuSwitchTracking(Mt, &MenuInfo, Index);
+              MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
             }
 
           /* If the popup menu is not already "popped" */
@@ -2714,7 +2762,7 @@ MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
        if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) &&
            !(ItemInfo.fType & MF_SEPARATOR))
        {
-           MenuSwitchTracking(Mt, &MenuInfo, Index);
+           MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
         if (!(ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)))
                Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
        }
@@ -2763,7 +2811,7 @@ MenuGetSubPopup(HMENU Menu)
  * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
  */
 static LRESULT FASTCALL
-MenuDoNextMenu(MTRACKER* Mt, UINT Vk)
+MenuDoNextMenu(MTRACKER* Mt, UINT Vk, UINT wFlags)
 {
   ROSMENUINFO TopMenuInfo;
   ROSMENUINFO MenuInfo;
@@ -2858,7 +2906,7 @@ MenuDoNextMenu(MTRACKER* Mt, UINT Vk)
                          FALSE, 0 );
           if (Mt->CurrentMenu != Mt->TopMenu)
             {
-              MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE);
+              MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
             }
         }
 
@@ -2949,7 +2997,7 @@ MenuKeyEscape(MTRACKER *Mt, UINT Flags)
 
           if (MenuGetRosMenuInfo(&MenuInfo, MenuPrev))
             {
-              MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, TRUE);
+              MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, TRUE, Flags);
             }
           Mt->CurrentMenu = MenuPrev;
           EndMenu = FALSE;
@@ -3001,7 +3049,7 @@ MenuKeyLeft(MTRACKER* Mt, UINT Flags)
     {
       return;
     }
-  MenuHideSubPopups(Mt->OwnerWnd, &PrevMenuInfo, TRUE);
+  MenuHideSubPopups(Mt->OwnerWnd, &PrevMenuInfo, TRUE, Flags);
   Mt->CurrentMenu = MenuPrev;
 
   if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
@@ -3012,7 +3060,7 @@ MenuKeyLeft(MTRACKER* Mt, UINT Flags)
     {
       /* move menu bar selection if no more popups are left */
 
-      if (! MenuDoNextMenu(Mt, VK_LEFT))
+      if (! MenuDoNextMenu(Mt, VK_LEFT, Flags))
         {
           MenuMoveSelection(Mt->OwnerWnd, &TopMenuInfo, ITEM_PREV);
         }
@@ -3082,7 +3130,7 @@ static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags)
     {
       if (Mt->CurrentMenu != Mt->TopMenu)
         {
-          MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE );
+          MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
           hmenutmp = Mt->CurrentMenu = Mt->TopMenu;
         }
       else
@@ -3091,7 +3139,7 @@ static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags)
         }
 
       /* try to move to the next item */
-      if ( !MenuDoNextMenu(Mt, VK_RIGHT))
+      if ( !MenuDoNextMenu(Mt, VK_RIGHT, Flags))
           MenuMoveSelection(Mt->OwnerWnd, &MenuInfo, ITEM_NEXT);
 
       if ( hmenutmp || Mt->TrackFlags & TF_SUSPENDPOPUP )
@@ -3120,6 +3168,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
     BOOL fRemove;
     INT executedMenuId = -1;
     MTRACKER mt;
+    HWND capture_win;
     BOOL enterIdleSent = FALSE;
 
     mt.TrackFlags = 0;
@@ -3135,6 +3184,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
 
     if (!IsMenu(hmenu))
     {
+        WARN("Invalid menu handle %p\n", hmenu);
         SetLastError( ERROR_INVALID_MENU_HANDLE );
         return FALSE;
     }
@@ -3152,12 +3202,16 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
         fEndMenu = !fRemove;
     }
 
-    SetCapture(mt.OwnerWnd);
-    (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, mt.OwnerWnd);
+    if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
+
+    /* owner may not be visible when tracking a popup, so use the menu itself */
+    capture_win = (wFlags & TPM_POPUPMENU) ? MenuInfo.Wnd : mt.OwnerWnd;
+    (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1
+    SetCapture(capture_win);                                          // 2
 
-    ERR("MenuTrackMenu 1\n");
     while (! fEndMenu)
     {
+        BOOL ErrorExit = FALSE;
         PVOID menu = ValidateHandle(mt.CurrentMenu, VALIDATE_TYPE_MENU);
         if (!menu) /* sometimes happens if I do a window manager close */
            break;
@@ -3175,9 +3229,15 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
             }
             else
             {
+                /* ReactOS Check */
+                if (!ValidateHwnd(mt.OwnerWnd) || !ValidateHwnd(MenuInfo.Wnd))
+                {
+                   ErrorExit = TRUE; // Do not wait on dead windows, now test_capture_4 works.
+                   break;
+                }
                 if (!enterIdleSent)
                 {
-                  HWND win = (wFlags & TPM_ENTERIDLEEX) && (MenuInfo.Flags & MF_POPUP) ? MenuInfo.Wnd : NULL;
+                  HWND win = MenuInfo.Flags & MF_POPUP ? MenuInfo.Wnd : NULL;
                   enterIdleSent = TRUE;
                   SendMessageW( mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) win);
                 }
@@ -3185,6 +3245,8 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
             }
         }
 
+        if (ErrorExit) break; // Gracefully dropout.
+
         /* check if EndMenu() tried to cancel us, by posting this message */
         if (msg.message == WM_CANCELMODE)
         {
@@ -3242,6 +3304,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
                     if (hmenu)
                     {
                         executedMenuId = MenuButtonUp( &mt, hmenu, wFlags);
+                        TRACE("executedMenuId %d\n", executedMenuId);
 
                     /* End the loop if executedMenuId is an item ID */
                     /* or if the job was done (executedMenuId = 0). */
@@ -3261,7 +3324,6 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
 
                     if (hmenu)
                         fEndMenu |= !MenuMouseMove( &mt, hmenu, wFlags );
-                    break;
 
                } /* switch(msg.message) - mouse */
            }
@@ -3415,10 +3477,11 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
         {
             if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
             {
-                MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE);
+                MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE, wFlags);
 
                 if (MenuInfo.Flags & MF_POPUP)
                 {
+                    IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
                     DestroyWindow(MenuInfo.Wnd);
                     MenuInfo.Wnd = NULL;
 
@@ -3453,11 +3516,21 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
 static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
 {
     ROSMENUINFO MenuInfo;
-    
+
     TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
 
     HideCaret(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 (MenuGetRosMenuInfo(&MenuInfo, hMenu))
+    {
+        MenuInfo.Wnd = hWnd;
+        MenuSetRosMenuInfo(&MenuInfo);
+    }
+
     /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
     if (!(wFlags & TPM_NONOTIFY))
        SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
@@ -3467,40 +3540,38 @@ static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT
     if (!(wFlags & TPM_NONOTIFY))
     {
        SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
+       /* If an app changed/recreated menu bar entries in WM_INITMENU
+        * menu sizes will be recalculated once the menu created/shown.
+        */
 
-       MenuGetRosMenuInfo(&MenuInfo, hMenu);
-
-        if (!MenuInfo.Height)
-        {
-            /* app changed/recreated menu bar entries in WM_INITMENU
-               Recalculate menu sizes else clicks will not work */
-            SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+       if (!MenuInfo.Height)
+       {
+          /* app changed/recreated menu bar entries in WM_INITMENU
+             Recalculate menu sizes else clicks will not work */
+             SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
                        SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
 
-        }
-        /* 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(MenuInfo.Self == hMenu)
-        {
-            MenuInfo.Wnd = hWnd;
-            MenuSetRosMenuInfo(&MenuInfo);
-        }
+       }
     }
 
+    IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART,
+                       hWnd,
+                       MenuInfo.Flags & MF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU,
+                       CHILDID_SELF, 0);
     return TRUE;
 }
 /***********************************************************************
  *           MenuExitTracking
  */
-static BOOL FASTCALL MenuExitTracking(HWND hWnd)
+static BOOL FASTCALL MenuExitTracking(HWND hWnd, BOOL bPopup)
 {
     TRACE("hwnd=%p\n", hWnd);
 
-    SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 );
+    IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, hWnd, OBJID_WINDOW, CHILDID_SELF, 0);
+    SendMessageW( hWnd, WM_EXITMENULOOP, bPopup, 0 );
     ShowCaret(0);
     top_popup = 0;
+    top_popup_hmenu = NULL;
     return TRUE;
 }
 
@@ -3512,7 +3583,7 @@ static BOOL FASTCALL MenuExitTracking(HWND hWnd)
 VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt)
 {
     HMENU hMenu = (ht == HTSYSMENU) ? NtUserGetSystemMenu( hWnd, FALSE) : GetMenu(hWnd);
-    UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+    UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
 
     TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
 
@@ -3527,7 +3598,7 @@ VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt)
 
         MenuInitTracking(hWnd, hMenu, FALSE, wFlags);
         MenuTrackMenu(hMenu, wFlags, pt.x, pt.y, hWnd, NULL);
-        MenuExitTracking(hWnd);
+        MenuExitTracking(hWnd, FALSE);
     }
 }
 
@@ -3542,7 +3613,7 @@ VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar)
     UINT uItem = NO_SELECTED_ITEM;
     HMENU hTrackMenu;
     ROSMENUINFO MenuInfo;
-    UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+    UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON;
 
     TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
 
@@ -3586,23 +3657,17 @@ VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar)
 
     MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 );
 
-    if (wParam & HTSYSMENU)
-    {
-        /* prevent sysmenu activation for managed windows on Alt down/up */
-//        if (GetPropA( hwnd, "__wine_x11_managed" ))
-            wFlags |= TF_ENDMENU; /* schedule end of menu tracking */
-    }
-    else
+    if (!(wParam & HTSYSMENU) || wChar == ' ')
     {
         if( uItem == NO_SELECTED_ITEM )
             MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT );
         else
-            PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
+            PostMessageW( hwnd, WM_KEYDOWN, VK_RETURN, 0 );
     }
 
 track_menu:
     MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
-    MenuExitTracking( hwnd );
+    MenuExitTracking( hwnd, FALSE );
 
 }
 
@@ -3611,19 +3676,9 @@ track_menu:
  */
 BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y,
                               HWND Wnd, LPTPMPARAMS Tpm)
-{
-  /* Not fully implemented */
-  return TrackPopupMenu(Menu, Flags, x, y, 0, Wnd,
-                        NULL != Tpm ? &Tpm->rcExclude : NULL);
-}
-
-/**********************************************************************
- *           TrackPopupMenu     (USER32.@)
- */
-BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
-                            int Reserved, HWND Wnd, CONST RECT *Rect)
 {
     BOOL ret = FALSE;
+    ROSMENUINFO MenuInfo;
 
     if (!IsMenu(Menu))
     {
@@ -3631,6 +3686,19 @@ BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
       return FALSE;
     }
 
+    /* ReactOS Check */
+    if (!ValidateHwnd(Wnd))
+    {
+       return FALSE;
+    }
+
+    MenuGetRosMenuInfo(&MenuInfo, Menu);
+    if (IsWindow(MenuInfo.Wnd))
+    {
+        SetLastError( ERROR_POPUP_ALREADY_ACTIVE );
+        return FALSE;
+    }
+
     MenuInitTracking(Wnd, Menu, TRUE, Flags);
 
     /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
@@ -3638,11 +3706,21 @@ BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
         SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0);
 
     if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 ))
-        ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect);
-    MenuExitTracking(Wnd);
+       ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd,
+                           Tpm ? &Tpm->rcExclude : NULL);
+    MenuExitTracking(Wnd, TRUE);
     return ret;
 }
 
+/**********************************************************************
+ *           TrackPopupMenu     (USER32.@)
+ */
+BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
+                            int Reserved, HWND Wnd, CONST RECT *Rect)
+{
+    return TrackPopupMenuEx( Menu, Flags, x, y, Wnd, NULL);
+}
+
 /*
  *  From MSDN:
  *  The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
@@ -3692,7 +3770,7 @@ MenuSetItemData(
   {
     mii->fType |= MFT_OWNERDRAW;
     mii->fMask |= MIIM_DATA;
-    mii->dwItemData = (DWORD) NewItem;
+    mii->dwItemData = (DWORD_PTR) NewItem;
   }
   else if (Flags & MF_SEPARATOR)
   {
@@ -3795,10 +3873,10 @@ NTSTATUS WINAPI
 User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength)
 {
   PLOADMENU_CALLBACK_ARGUMENTS Common;
-  LRESULT Result;  
+  LRESULT Result;
 
   Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments;
-  
+
   Result = (LRESULT)LoadMenuW( Common->hModule,
                                IS_INTRESOURCE(Common->MenuName[0]) ?
                                   MAKEINTRESOURCE(Common->MenuName[0]) :
@@ -4025,17 +4103,12 @@ DrawMenuBar(HWND hWnd)
   MenuGetRosMenuInfo(&MenuInfo, hMenu);
   MenuInfo.Height = 0; // make sure to recalc size
   MenuSetRosMenuInfo(&MenuInfo);
-  /* The wine method doesn't work and I suspect it's more effort
-     then hackfix solution
+  
   SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
                   SWP_NOZORDER | SWP_FRAMECHANGED );
-  return TRUE;*/
-  // FIXME: hackfix
-  DefWndNCPaint(hWnd,(HRGN)-1,-1);
   return TRUE;
 }
 
-
 /*
  * @implemented
  */
@@ -4057,7 +4130,25 @@ EndMenu(VOID)
   guii.cbSize = sizeof(GUITHREADINFO);
   if(GetGUIThreadInfo(GetCurrentThreadId(), &guii) && guii.hwndMenuOwner)
   {
-    PostMessageW(guii.hwndMenuOwner, WM_CANCELMODE, 0, 0);
+    if (!fEndMenu &&
+         top_popup &&
+         guii.hwndMenuOwner != top_popup )
+    {
+       ERR("Capture GUI pti hWnd does not match top_popup!\n");
+    }
+  }
+
+  /* if we are in the menu code, and it is active */
+  if (!fEndMenu && top_popup)
+  {
+      /* terminate the menu handling code */
+      fEndMenu = TRUE;
+
+      /* needs to be posted to wakeup the internal menu handler */
+      /* which will now terminate the menu, in the event that */
+      /* the main window was minimized, or lost focus, so we */
+      /* don't end up with an orphaned menu */
+      PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
   }
   return TRUE;
 }
@@ -4074,7 +4165,7 @@ GetMenu(HWND hWnd)
        if (!Wnd)
                return NULL;
 
-       return (HMENU)Wnd->IDMenu;
+       return UlongToHandle(Wnd->IDMenu);
 }