[CMAKE]
[reactos.git] / dll / win32 / user32 / windows / menu.c
index c9e87de..34eaac9 100644 (file)
@@ -66,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;
@@ -86,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 */
@@ -516,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->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);
 }
 
@@ -782,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;
 
@@ -862,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);
@@ -1164,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)
@@ -1324,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 */
             {
@@ -1495,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++)
@@ -1582,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);
 
@@ -1626,7 +1615,7 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl
     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);
@@ -1797,9 +1786,24 @@ 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)
     {
@@ -1839,6 +1843,9 @@ LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM l
           top_popup = NULL;
           top_popup_hmenu = NULL;
         }
+#ifdef __REACTOS__
+      NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+#endif
       break;
 
     case WM_SHOWWINDOW:
@@ -1860,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:
@@ -1873,6 +1880,18 @@ 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)
     {
@@ -1912,6 +1931,9 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
           top_popup = NULL;
           top_popup_hmenu = NULL;
         }
+#ifdef __REACTOS__
+      NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+#endif
       break;
 
     case WM_SHOWWINDOW:
@@ -3146,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;
@@ -3179,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;
@@ -3202,6 +3229,12 @@ 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 = MenuInfo.Flags & MF_POPUP ? MenuInfo.Wnd : NULL;
@@ -3212,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)
         {
@@ -3428,7 +3463,6 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
             PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
         else mt.TrackFlags &= ~TF_SKIPREMOVE;
     }
-    ERR("MenuTrackMenu 2\n");
 
     (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL);
     SetCapture(NULL);  /* release the capture */
@@ -3482,19 +3516,27 @@ 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 );
 
     SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
 
-    MenuGetRosMenuInfo(&MenuInfo, hMenu);
-
     if (!(wFlags & TPM_NONOTIFY))
     {
        SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
@@ -3512,16 +3554,6 @@ static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT
        }
     }
 
-    /* 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,
@@ -3625,18 +3657,12 @@ 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:
@@ -3652,13 +3678,27 @@ BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y,
                               HWND Wnd, LPTPMPARAMS Tpm)
 {
     BOOL ret = FALSE;
+    ROSMENUINFO MenuInfo;
 
-    if (!IsMenu(Menu))    
+    if (!IsMenu(Menu))
     {
       SetLastError( ERROR_INVALID_MENU_HANDLE );
       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 */
@@ -3833,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]) :
@@ -4063,13 +4103,9 @@ 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;
 }
 
@@ -4117,25 +4153,6 @@ EndMenu(VOID)
   return TRUE;
 }
 
-// So this one maybe one day it will be a callback!
-BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
-                                UINT wHilite )
-{
-    ROSMENUINFO MenuInfo;
-    ROSMENUITEMINFO mii;
-    TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
-    if (!hWnd)
-    {
-       SetLastError(ERROR_INVALID_WINDOW_HANDLE);
-       return FALSE;
-    }
-    if (!NtUserMenuItemInfo(hMenu, wItemID, wHilite, &mii, FALSE)) return FALSE;
-    if (!NtUserMenuInfo(hMenu, &MenuInfo, FALSE)) return FALSE;
-    if (MenuInfo.FocusedItem == wItemID) return TRUE;
-    MenuHideSubPopups( hWnd, &MenuInfo, FALSE, 0 );
-    MenuSelectItem( hWnd, &MenuInfo, wItemID, TRUE, 0 );
-    return TRUE;
-}
 
 /*
  * @implemented