4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
7 * Copyright 2005 Maxime Bellengé
8 * Copyright 2006 Phil Krylov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Note: the style MF_MOUSESELECT is used to mark popup items that
27 * have been selected, i.e. their popup menu is currently displayed.
28 * This is probably not the meaning this style has in MS-Windows.
30 * Note 2: where there is a difference, these menu API's are according
31 * the behavior of Windows 2k and Windows XP. Known differences with
32 * Windows 9x/ME are documented in the comments, in case an application
33 * is found to depend on the old behavior.
44 #include "wine/port.h"
53 #include "wine/winbase16.h"
54 #include "wine/winuser16.h"
56 #include "wine/server.h"
57 #include "wine/unicode.h"
60 #include "user_private.h"
61 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(menu);
64 WINE_DECLARE_DEBUG_CHANNEL(accel);
66 /* internal popup menu window messages */
68 #define MM_SETMENUHANDLE (WM_USER + 0)
69 #define MM_GETMENUHANDLE (WM_USER + 1)
71 /* Menu item structure */
73 /* ----------- MENUITEMINFO Stuff ----------- */
74 UINT fType; /* Item type. */
75 UINT fState; /* Item state. */
76 UINT_PTR wID; /* Item id. */
77 HMENU hSubMenu; /* Pop-up menu. */
78 HBITMAP hCheckBit; /* Bitmap when checked. */
79 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
80 LPWSTR text; /* Item text. */
81 ULONG_PTR dwItemData; /* Application defined. */
82 LPWSTR dwTypeData; /* depends on fMask */
83 HBITMAP hbmpItem; /* bitmap */
84 /* ----------- Wine stuff ----------- */
85 RECT rect; /* Item area (relative to menu window) */
86 UINT xTab; /* X position of text after Tab */
87 SIZE bmpsize; /* size needed for the HBMMENU_CALLBACK
91 /* Popup menu structure */
93 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
94 WORD wMagic; /* Magic number */
95 WORD Width; /* Width of the whole menu */
96 WORD Height; /* Height of the whole menu */
97 UINT nItems; /* Number of items in the menu */
98 HWND hWnd; /* Window containing the menu */
99 MENUITEM *items; /* Array of menu items */
100 UINT FocusedItem; /* Currently focused item */
101 HWND hwndOwner; /* window receiving the messages for ownerdraw */
102 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
103 BOOL bScrolling; /* Scroll arrows are active */
104 UINT nScrollPos; /* Current scroll position */
105 UINT nTotalHeight; /* Total height of menu items inside menu */
106 /* ------------ MENUINFO members ------ */
107 DWORD dwStyle; /* Extended menu style */
108 UINT cyMax; /* max height of the whole menu, 0 is screen height */
109 HBRUSH hbrBack; /* brush for menu background */
110 DWORD dwContextHelpID;
111 DWORD dwMenuData; /* application defined value */
112 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
113 SIZE maxBmpSize; /* Maximum size of the bitmap items */
114 } POPUPMENU, *LPPOPUPMENU;
116 /* internal flags for menu tracking */
118 #define TF_ENDMENU 0x0001
119 #define TF_SUSPENDPOPUP 0x0002
120 #define TF_SKIPREMOVE 0x0004
125 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
126 HMENU hTopMenu; /* initial menu */
127 HWND hOwnerWnd; /* where notifications are sent */
131 #define MENU_MAGIC 0x554d /* 'MU' */
136 /* Internal MENU_TrackMenu() flags */
137 #define TPM_INTERNAL 0xF0000000
138 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
139 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
140 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
142 /* Space between 2 columns */
143 #define MENU_COL_SPACE 4
145 /* top and bottom margins for popup menus */
146 #define MENU_TOP_MARGIN 3
147 #define MENU_BOTTOM_MARGIN 2
149 /* (other menu->FocusedItem values give the position of the focused item) */
150 #define NO_SELECTED_ITEM 0xffff
152 #define MENU_ITEM_TYPE(flags) \
153 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
155 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
156 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
157 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
159 #define IS_SYSTEM_MENU(menu) \
160 (!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
162 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
163 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
164 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
165 MF_POPUP | MF_SYSMENU | MF_HELP)
166 #define STATE_MASK (~TYPE_MASK)
168 #define WIN_ALLOWED_MENU(style) ((style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
170 static SIZE menucharsize;
171 static UINT ODitemheight; /* default owner drawn item height */
173 /* Use global popup window because there's no way 2 menus can
174 * be tracked at the same time. */
175 static HWND top_popup;
177 /* Flag set by EndMenu() to force an exit from menu tracking */
178 static BOOL fEndMenu = FALSE;
180 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
182 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont);
184 /*********************************************************************
185 * menu class descriptor
187 const struct builtin_class_descr MENU_builtin_class =
189 POPUPMENU_CLASS_ATOMA, /* name */
190 CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, /* style */
191 NULL, /* procA (winproc is Unicode only) */
192 PopupMenuWndProc, /* procW */
193 sizeof(HMENU), /* extra */
194 IDC_ARROW, /* cursor */
195 (HBRUSH)(COLOR_MENU+1) /* brush */
199 /***********************************************************************
200 * debug_print_menuitem
202 * Print a menuitem in readable form.
205 #define debug_print_menuitem(pre, mp, post) \
206 do { if (TRACE_ON(menu)) do_debug_print_menuitem(pre, mp, post); } while (0)
208 #define MENUOUT(text) \
209 TRACE("%s%s", (count++ ? "," : ""), (text))
211 #define MENUFLAG(bit,text) \
213 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
216 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
219 static const char * const hbmmenus[] = { "HBMMENU_CALLBACK", "", "HBMMENU_SYSTEM",
220 "HBMMENU_MBAR_RESTORE", "HBMMENU_MBAR_MINIMIZE", "UNKNOWN BITMAP", "HBMMENU_MBAR_CLOSE",
221 "HBMMENU_MBAR_CLOSE_D", "HBMMENU_MBAR_MINIMIZE_D", "HBMMENU_POPUP_CLOSE",
222 "HBMMENU_POPUP_RESTORE", "HBMMENU_POPUP_MAXIMIZE", "HBMMENU_POPUP_MINIMIZE"};
223 TRACE("%s ", prefix);
225 UINT flags = mp->fType;
226 TRACE( "{ ID=0x%x", mp->wID);
228 TRACE( ", Sub=%p", mp->hSubMenu);
232 MENUFLAG( MFT_SEPARATOR, "sep");
233 MENUFLAG( MFT_OWNERDRAW, "own");
234 MENUFLAG( MFT_BITMAP, "bit");
235 MENUFLAG(MF_POPUP, "pop");
236 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
237 MENUFLAG(MFT_MENUBREAK, "brk");
238 MENUFLAG(MFT_RADIOCHECK, "radio");
239 MENUFLAG(MFT_RIGHTORDER, "rorder");
240 MENUFLAG(MF_SYSMENU, "sys");
241 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
243 TRACE( "+0x%x", flags);
249 MENUFLAG(MFS_GRAYED, "grey");
250 MENUFLAG(MFS_DEFAULT, "default");
251 MENUFLAG(MFS_DISABLED, "dis");
252 MENUFLAG(MFS_CHECKED, "check");
253 MENUFLAG(MFS_HILITE, "hi");
254 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
255 MENUFLAG(MF_MOUSESELECT, "mouse");
257 TRACE( "+0x%x", flags);
260 TRACE( ", Chk=%p", mp->hCheckBit);
262 TRACE( ", Unc=%p", mp->hUnCheckBit);
264 TRACE( ", Text=%s", debugstr_w(mp->text));
266 TRACE( ", ItemData=0x%08lx", mp->dwItemData);
269 if( IS_MAGIC_BITMAP(mp->hbmpItem))
270 TRACE( ", hbitmap=%s", hbmmenus[ (INT_PTR)mp->hbmpItem + 1]);
272 TRACE( ", hbitmap=%p", mp->hbmpItem);
277 TRACE(" %s\n", postfix);
284 /***********************************************************************
287 * Validate the given menu handle and returns the menu structure pointer.
289 static POPUPMENU *MENU_GetMenu(HMENU hMenu)
291 POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
292 if (!menu || menu->wMagic != MENU_MAGIC)
294 WARN("invalid menu handle=%p, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
300 /***********************************************************************
303 * Get the system menu of a window
305 static HMENU get_win_sys_menu( HWND hwnd )
308 WND *win = WIN_GetPtr( hwnd );
309 if (win && win != WND_OTHER_PROCESS && win != WND_DESKTOP)
312 WIN_ReleasePtr( win );
317 /***********************************************************************
320 static HFONT get_menu_font( BOOL bold )
322 static HFONT hMenuFont, hMenuFontBold;
324 HFONT ret = bold ? hMenuFontBold : hMenuFont;
328 NONCLIENTMETRICSW ncm;
331 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
332 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0);
336 ncm.lfMenuFont.lfWeight += 300;
337 if (ncm.lfMenuFont.lfWeight > 1000) ncm.lfMenuFont.lfWeight = 1000;
339 if (!(ret = CreateFontIndirectW( &ncm.lfMenuFont ))) return 0;
340 prev = InterlockedCompareExchangePointer( (void **)(bold ? &hMenuFontBold : &hMenuFont),
344 /* another thread beat us to it */
352 /***********************************************************************
355 static HBITMAP get_arrow_bitmap(void)
357 static HBITMAP arrow_bitmap;
359 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
363 /***********************************************************************
364 * get_down_arrow_bitmap
366 static HBITMAP get_down_arrow_bitmap(void)
368 static HBITMAP arrow_bitmap;
370 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW));
374 /***********************************************************************
375 * get_down_arrow_inactive_bitmap
377 static HBITMAP get_down_arrow_inactive_bitmap(void)
379 static HBITMAP arrow_bitmap;
381 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI));
385 /***********************************************************************
386 * get_up_arrow_bitmap
388 static HBITMAP get_up_arrow_bitmap(void)
390 static HBITMAP arrow_bitmap;
392 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW));
396 /***********************************************************************
397 * get_up_arrow_inactive_bitmap
399 static HBITMAP get_up_arrow_inactive_bitmap(void)
401 static HBITMAP arrow_bitmap;
403 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI));
407 /***********************************************************************
410 * Return the default system menu.
412 static HMENU MENU_CopySysPopup(void)
414 static const WCHAR sysmenuW[] = {'S','Y','S','M','E','N','U',0};
415 HMENU hMenu = LoadMenuW(user32_module, sysmenuW);
418 POPUPMENU* menu = MENU_GetMenu(hMenu);
419 menu->wFlags |= MF_SYSMENU | MF_POPUP;
420 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
423 ERR("Unable to load default system menu\n" );
425 TRACE("returning %p.\n", hMenu );
431 /**********************************************************************
434 * Create a copy of the system menu. System menu in Windows is
435 * a special menu bar with the single entry - system menu popup.
436 * This popup is presented to the outside world as a "system menu".
437 * However, the real system menu handle is sometimes seen in the
438 * WM_MENUSELECT parameters (and Word 6 likes it this way).
440 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
444 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd, hPopupMenu);
445 if ((hMenu = CreateMenu()))
447 POPUPMENU *menu = MENU_GetMenu(hMenu);
448 menu->wFlags = MF_SYSMENU;
449 menu->hWnd = WIN_GetFullHandle( hWnd );
450 TRACE("hWnd %p (hMenu %p)\n", menu->hWnd, hMenu);
453 hPopupMenu = MENU_CopySysPopup();
457 if (GetClassLongW(hWnd, GCL_STYLE) & CS_NOCLOSE)
458 DeleteMenu(hPopupMenu, SC_CLOSE, MF_BYCOMMAND);
460 InsertMenuW( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION,
461 (UINT_PTR)hPopupMenu, NULL );
463 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
464 menu->items[0].fState = 0;
465 if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
467 TRACE("hMenu=%p (hPopup %p)\n", hMenu, hPopupMenu );
470 DestroyMenu( hMenu );
472 ERR("failed to load system menu!\n");
477 /***********************************************************************
478 * MENU_InitSysMenuPopup
480 * Grey the appropriate items in System menu.
482 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
486 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
487 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
488 gray = ((style & WS_MAXIMIZE) != 0);
489 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
490 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
491 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
492 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
493 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
494 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
495 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
496 gray = (clsStyle & CS_NOCLOSE) != 0;
498 /* The menu item must keep its state if it's disabled */
500 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
504 /******************************************************************************
506 * UINT MENU_GetStartOfNextColumn(
509 *****************************************************************************/
511 static UINT MENU_GetStartOfNextColumn(
514 POPUPMENU *menu = MENU_GetMenu(hMenu);
518 return NO_SELECTED_ITEM;
520 i = menu->FocusedItem + 1;
521 if( i == NO_SELECTED_ITEM )
524 for( ; i < menu->nItems; ++i ) {
525 if (menu->items[i].fType & MF_MENUBARBREAK)
529 return NO_SELECTED_ITEM;
533 /******************************************************************************
535 * UINT MENU_GetStartOfPrevColumn(
538 *****************************************************************************/
540 static UINT MENU_GetStartOfPrevColumn(
543 POPUPMENU *menu = MENU_GetMenu(hMenu);
547 return NO_SELECTED_ITEM;
549 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
550 return NO_SELECTED_ITEM;
552 /* Find the start of the column */
554 for(i = menu->FocusedItem; i != 0 &&
555 !(menu->items[i].fType & MF_MENUBARBREAK);
559 return NO_SELECTED_ITEM;
561 for(--i; i != 0; --i) {
562 if (menu->items[i].fType & MF_MENUBARBREAK)
566 TRACE("ret %d.\n", i );
573 /***********************************************************************
576 * Find a menu item. Return a pointer on the item, and modifies *hmenu
577 * in case the item was in a sub-menu.
579 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
582 MENUITEM *fallback = NULL;
583 UINT fallback_pos = 0;
586 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
587 if (wFlags & MF_BYPOSITION)
589 if (*nPos >= menu->nItems) return NULL;
590 return &menu->items[*nPos];
594 MENUITEM *item = menu->items;
595 for (i = 0; i < menu->nItems; i++, item++)
597 if (item->fType & MF_POPUP)
599 HMENU hsubmenu = item->hSubMenu;
600 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
606 else if (item->wID == *nPos)
608 /* fallback to this item if nothing else found */
613 else if (item->wID == *nPos)
622 *nPos = fallback_pos;
627 /***********************************************************************
630 * Find a Sub menu. Return the position of the submenu, and modifies
631 * *hmenu in case it is found in another sub-menu.
632 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
634 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
639 if (((*hmenu)==(HMENU)0xffff) ||
640 (!(menu = MENU_GetMenu(*hmenu))))
641 return NO_SELECTED_ITEM;
643 for (i = 0; i < menu->nItems; i++, item++) {
644 if(!(item->fType & MF_POPUP)) continue;
645 if (item->hSubMenu == hSubTarget) {
649 HMENU hsubmenu = item->hSubMenu;
650 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
651 if (pos != NO_SELECTED_ITEM) {
657 return NO_SELECTED_ITEM;
660 /***********************************************************************
663 static void MENU_FreeItemData( MENUITEM* item )
666 HeapFree( GetProcessHeap(), 0, item->text );
669 /***********************************************************************
670 * MENU_AdjustMenuItemRect
672 * Adjust menu item rectangle according to scrolling state.
675 MENU_AdjustMenuItemRect(const POPUPMENU *menu, LPRECT rect)
677 if (menu->bScrolling)
679 UINT arrow_bitmap_width, arrow_bitmap_height;
682 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
683 arrow_bitmap_width = bmp.bmWidth;
684 arrow_bitmap_height = bmp.bmHeight;
685 rect->top += arrow_bitmap_height - menu->nScrollPos;
686 rect->bottom += arrow_bitmap_height - menu->nScrollPos;
691 /***********************************************************************
692 * MENU_FindItemByCoords
694 * Find the item at the specified coordinates (screen coords). Does
695 * not work for child windows and therefore should not be called for
696 * an arbitrary system menu.
698 static MENUITEM *MENU_FindItemByCoords( const POPUPMENU *menu,
699 POINT pt, UINT *pos )
706 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
707 pt.x -= wrect.left;pt.y -= wrect.top;
709 for (i = 0; i < menu->nItems; i++, item++)
712 MENU_AdjustMenuItemRect(menu, &rect);
713 if ((pt.x >= rect.left) && (pt.x < rect.right) &&
714 (pt.y >= rect.top) && (pt.y < rect.bottom))
724 /***********************************************************************
727 * Find the menu item selected by a key press.
728 * Return item id, -1 if none, -2 if we should close the menu.
730 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
731 WCHAR key, BOOL forceMenuChar )
733 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)key, key, hmenu );
735 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
739 POPUPMENU *menu = MENU_GetMenu( hmenu );
740 MENUITEM *item = menu->items;
747 for (i = 0; i < menu->nItems; i++, item++)
751 WCHAR *p = item->text - 2;
754 p = strchrW (p + 2, '&');
756 while (p != NULL && p [1] == '&');
757 if (p && (toupperW(p[1]) == toupperW(key))) return i;
761 menuchar = SendMessageW( hwndOwner, WM_MENUCHAR,
762 MAKEWPARAM( key, menu->wFlags ), (LPARAM)hmenu );
763 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
764 if (HIWORD(menuchar) == 1) return (UINT)(-2);
770 /***********************************************************************
771 * MENU_GetBitmapItemSize
773 * Get the size of a bitmap item.
775 static void MENU_GetBitmapItemSize( MENUITEM *lpitem, SIZE *size,
779 HBITMAP bmp = lpitem->hbmpItem;
781 size->cx = size->cy = 0;
783 /* check if there is a magic menu item associated with this item */
784 switch( (INT_PTR) bmp )
786 case (INT_PTR)HBMMENU_CALLBACK:
788 MEASUREITEMSTRUCT measItem;
789 measItem.CtlType = ODT_MENU;
791 measItem.itemID = lpitem->wID;
792 measItem.itemWidth = lpitem->rect.right - lpitem->rect.left;
793 measItem.itemHeight = lpitem->rect.bottom - lpitem->rect.top;
794 measItem.itemData = lpitem->dwItemData;
795 SendMessageW( hwndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
796 size->cx = measItem.itemWidth;
797 size->cy = measItem.itemHeight;
801 case (INT_PTR)HBMMENU_SYSTEM:
802 if (lpitem->dwItemData)
804 bmp = (HBITMAP)lpitem->dwItemData;
808 case (INT_PTR)HBMMENU_MBAR_RESTORE:
809 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
810 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
811 case (INT_PTR)HBMMENU_MBAR_CLOSE:
812 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
813 size->cx = GetSystemMetrics( SM_CYMENU ) - 4;
816 case (INT_PTR)HBMMENU_POPUP_CLOSE:
817 case (INT_PTR)HBMMENU_POPUP_RESTORE:
818 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
819 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
820 FIXME("Magic %p not implemented\n", bmp );
823 if (GetObjectW(bmp, sizeof(bm), &bm ))
825 size->cx = bm.bmWidth;
826 size->cy = bm.bmHeight;
830 /***********************************************************************
831 * MENU_DrawBitmapItem
833 * Draw a bitmap item.
835 static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect,
836 HMENU hmenu, HWND hwndOwner, UINT odaction, BOOL menuBar)
842 int w = rect->right - rect->left;
843 int h = rect->bottom - rect->top;
846 HBITMAP hbmToDraw = lpitem->hbmpItem;
849 /* Check if there is a magic menu item associated with this item */
850 if (IS_MAGIC_BITMAP(hbmToDraw))
855 switch((INT_PTR)hbmToDraw)
857 case (INT_PTR)HBMMENU_SYSTEM:
858 if (lpitem->dwItemData)
860 bmp = (HBITMAP)lpitem->dwItemData;
861 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
865 static HBITMAP hBmpSysMenu;
867 if (!hBmpSysMenu) hBmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
869 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
870 /* only use right half of the bitmap */
871 bmp_xoffset = bm.bmWidth / 2;
872 bm.bmWidth -= bmp_xoffset;
875 case (INT_PTR)HBMMENU_MBAR_RESTORE:
876 flags = DFCS_CAPTIONRESTORE;
878 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
879 flags = DFCS_CAPTIONMIN;
881 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
882 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
884 case (INT_PTR)HBMMENU_MBAR_CLOSE:
885 flags = DFCS_CAPTIONCLOSE;
887 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
888 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
890 case (INT_PTR)HBMMENU_CALLBACK:
892 DRAWITEMSTRUCT drawItem;
893 drawItem.CtlType = ODT_MENU;
895 drawItem.itemID = lpitem->wID;
896 drawItem.itemAction = odaction;
897 drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
898 drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
899 drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
900 drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
901 drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
902 drawItem.hwndItem = (HWND)hmenu;
904 drawItem.itemData = lpitem->dwItemData;
905 drawItem.rcItem = *rect;
906 SendMessageW( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem);
910 case (INT_PTR)HBMMENU_POPUP_CLOSE:
911 case (INT_PTR)HBMMENU_POPUP_RESTORE:
912 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
913 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
915 FIXME("Magic %p not implemented\n", hbmToDraw);
919 InflateRect( &r, -1, -1 );
920 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
921 DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
925 if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
928 hdcMem = CreateCompatibleDC( hdc );
929 SelectObject( hdcMem, bmp );
931 /* handle fontsize > bitmap_height */
932 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
934 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
935 if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem)
936 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
937 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
942 /***********************************************************************
945 * Calculate the size of the menu item and store it in lpitem->rect.
947 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
948 INT orgX, INT orgY, BOOL menuBar, POPUPMENU* lppop )
951 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
952 UINT arrow_bitmap_width;
956 TRACE("dc=%p owner=%p (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
957 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
958 (menuBar ? " (MenuBar)" : ""));
960 GetObjectW( get_arrow_bitmap(), sizeof(bm), &bm );
961 arrow_bitmap_width = bm.bmWidth;
963 /* not done in Menu_Init: GetDialogBaseUnits() breaks there */
964 if( !menucharsize.cx ) {
965 menucharsize.cx = GdiGetCharDimensions( hdc, NULL, &menucharsize.cy );
966 /* Win95/98/ME will use menucharsize.cy here. Testing is possible
967 * but it is unlikely an application will depend on that */
968 ODitemheight = HIWORD( GetDialogBaseUnits());
971 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
973 if (lpitem->fType & MF_OWNERDRAW)
975 MEASUREITEMSTRUCT mis;
976 mis.CtlType = ODT_MENU;
978 mis.itemID = lpitem->wID;
979 mis.itemData = lpitem->dwItemData;
980 mis.itemHeight = ODitemheight;
982 SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
983 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
984 * width of a menufont character to the width of an owner-drawn menu.
986 lpitem->rect.right += mis.itemWidth + 2 * menucharsize.cx;
988 /* under at least win95 you seem to be given a standard
989 height for the menu and the height value is ignored */
990 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENUSIZE);
992 lpitem->rect.bottom += mis.itemHeight;
994 TRACE("id=%04x size=%ldx%ld\n",
995 lpitem->wID, lpitem->rect.right-lpitem->rect.left,
996 lpitem->rect.bottom-lpitem->rect.top);
1000 if (lpitem->fType & MF_SEPARATOR)
1002 lpitem->rect.bottom += GetSystemMetrics( SM_CYMENUSIZE)/2;
1004 lpitem->rect.right += arrow_bitmap_width + menucharsize.cx;
1012 if (lpitem->hbmpItem) {
1015 MENU_GetBitmapItemSize(lpitem, &size, hwndOwner);
1016 /* Keep the size of the bitmap in callback mode to be able
1017 * to draw it correctly */
1018 lpitem->bmpsize = size;
1019 lppop->maxBmpSize.cx = max( lppop->maxBmpSize.cx, size.cx);
1020 lppop->maxBmpSize.cy = max( lppop->maxBmpSize.cy, size.cy);
1021 lpitem->rect.right += size.cx + 2;
1022 itemheight = size.cy + 2;
1024 if( !(lppop->dwStyle & MNS_NOCHECK))
1025 lpitem->rect.right += check_bitmap_width;
1026 lpitem->rect.right += 4 + menucharsize.cx;
1027 lpitem->xTab = lpitem->rect.right;
1028 lpitem->rect.right += arrow_bitmap_width;
1029 } else if (lpitem->hbmpItem) { /* menuBar */
1032 MENU_GetBitmapItemSize( lpitem, &size, hwndOwner );
1033 lpitem->bmpsize = size;
1034 lpitem->rect.right += size.cx;
1035 if( lpitem->text) lpitem->rect.right += 2;
1036 itemheight = size.cy;
1039 /* it must be a text item - unless it's the system menu */
1040 if (!(lpitem->fType & MF_SYSMENU) && lpitem->text) {
1041 HFONT hfontOld = NULL;
1042 RECT rc = lpitem->rect;
1043 LONG txtheight, txtwidth;
1045 if ( lpitem->fState & MFS_DEFAULT ) {
1046 hfontOld = SelectObject( hdc, get_menu_font(TRUE) );
1049 txtheight = DrawTextW( hdc, lpitem->text, -1, &rc,
1050 DT_SINGLELINE|DT_CALCRECT);
1051 lpitem->rect.right += rc.right - rc.left;
1052 itemheight = max( max( itemheight, txtheight),
1053 GetSystemMetrics( SM_CYMENU) - 1);
1054 lpitem->rect.right += 2 * menucharsize.cx;
1056 if ((p = strchrW( lpitem->text, '\t' )) != NULL) {
1059 int n = (int)( p - lpitem->text);
1060 /* Item contains a tab (only meaningful in popup menus) */
1061 /* get text size before the tab */
1062 txtheight = DrawTextW( hdc, lpitem->text, n, &rc,
1063 DT_SINGLELINE|DT_CALCRECT);
1064 txtwidth = rc.right - rc.left;
1065 p += 1; /* advance past the Tab */
1066 /* get text size after the tab */
1067 tmpheight = DrawTextW( hdc, p, -1, &tmprc,
1068 DT_SINGLELINE|DT_CALCRECT);
1069 lpitem->xTab += txtwidth;
1070 txtheight = max( txtheight, tmpheight);
1071 txtwidth += menucharsize.cx + /* space for the tab */
1072 tmprc.right - tmprc.left; /* space for the short cut */
1074 txtheight = DrawTextW( hdc, lpitem->text, -1, &rc,
1075 DT_SINGLELINE|DT_CALCRECT);
1076 txtwidth = rc.right - rc.left;
1077 lpitem->xTab += txtwidth;
1079 lpitem->rect.right += 2 + txtwidth;
1080 itemheight = max( itemheight,
1081 max( txtheight + 2, menucharsize.cy + 4));
1083 if (hfontOld) SelectObject (hdc, hfontOld);
1084 } else if( menuBar) {
1085 itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1);
1087 lpitem->rect.bottom += itemheight;
1088 TRACE("%s\n", wine_dbgstr_rect( &lpitem->rect));
1092 /***********************************************************************
1093 * MENU_GetMaxPopupHeight
1096 MENU_GetMaxPopupHeight(LPPOPUPMENU lppop)
1099 return lppop->cyMax;
1100 return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER);
1104 /***********************************************************************
1105 * MENU_PopupMenuCalcSize
1107 * Calculate the size of a popup menu.
1109 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
1114 int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
1116 lppop->Width = lppop->Height = 0;
1117 if (lppop->nItems == 0) return;
1120 SelectObject( hdc, get_menu_font(FALSE));
1125 lppop->maxBmpSize.cx = 0;
1126 lppop->maxBmpSize.cy = 0;
1128 while (start < lppop->nItems)
1130 lpitem = &lppop->items[start];
1132 if( lpitem->fType & MF_MENUBREAK)
1133 orgX += MENU_COL_SPACE;
1134 orgY = MENU_TOP_MARGIN;
1136 maxTab = maxTabWidth = 0;
1137 /* Parse items until column break or end of menu */
1138 for (i = start; i < lppop->nItems; i++, lpitem++)
1141 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1143 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE, lppop );
1145 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
1146 maxX = max( maxX, lpitem->rect.right );
1147 orgY = lpitem->rect.bottom;
1148 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1150 maxTab = max( maxTab, lpitem->xTab );
1151 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
1155 /* Finish the column (set all items to the largest width found) */
1156 maxX = max( maxX, maxTab + maxTabWidth );
1157 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
1159 lpitem->rect.right = maxX;
1160 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1161 lpitem->xTab = maxTab;
1164 lppop->Height = max( lppop->Height, orgY );
1167 lppop->Width = maxX;
1169 /* space for 3d border */
1170 lppop->Height += MENU_BOTTOM_MARGIN;
1173 /* Adjust popup height if it exceeds maximum */
1174 maxHeight = MENU_GetMaxPopupHeight(lppop);
1175 lppop->nTotalHeight = lppop->Height - MENU_TOP_MARGIN;
1176 if (lppop->Height >= maxHeight)
1178 lppop->Height = maxHeight;
1179 lppop->bScrolling = TRUE;
1183 lppop->bScrolling = FALSE;
1186 ReleaseDC( 0, hdc );
1190 /***********************************************************************
1191 * MENU_MenuBarCalcSize
1193 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1194 * height is off by 1 pixel which causes lengthy window relocations when
1195 * active document window is maximized/restored.
1197 * Calculate the size of the menu bar.
1199 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1200 LPPOPUPMENU lppop, HWND hwndOwner )
1203 int start, i, orgX, orgY, maxY, helpPos;
1205 if ((lprect == NULL) || (lppop == NULL)) return;
1206 if (lppop->nItems == 0) return;
1207 TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
1208 lppop->Width = lprect->right - lprect->left;
1210 maxY = lprect->top+1;
1213 lppop->maxBmpSize.cx = 0;
1214 lppop->maxBmpSize.cy = 0;
1215 while (start < lppop->nItems)
1217 lpitem = &lppop->items[start];
1218 orgX = lprect->left;
1221 /* Parse items until line break or end of menu */
1222 for (i = start; i < lppop->nItems; i++, lpitem++)
1224 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
1226 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1228 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY );
1229 debug_print_menuitem (" item: ", lpitem, "");
1230 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE, lppop );
1232 if (lpitem->rect.right > lprect->right)
1234 if (i != start) break;
1235 else lpitem->rect.right = lprect->right;
1237 maxY = max( maxY, lpitem->rect.bottom );
1238 orgX = lpitem->rect.right;
1241 /* Finish the line (set all items to the largest height found) */
1242 while (start < i) lppop->items[start++].rect.bottom = maxY;
1245 lprect->bottom = maxY;
1246 lppop->Height = lprect->bottom - lprect->top;
1248 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1249 /* the last item (if several lines, only move the last line) */
1250 lpitem = &lppop->items[lppop->nItems-1];
1251 orgY = lpitem->rect.top;
1252 orgX = lprect->right;
1253 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1254 if ( (helpPos==-1) || (helpPos>i) )
1256 if (lpitem->rect.top != orgY) break; /* Other line */
1257 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1258 lpitem->rect.left += orgX - lpitem->rect.right;
1259 lpitem->rect.right = orgX;
1260 orgX = lpitem->rect.left;
1265 /***********************************************************************
1266 * MENU_DrawScrollArrows
1268 * Draw scroll arrows.
1271 MENU_DrawScrollArrows(LPPOPUPMENU lppop, HDC hdc)
1273 HDC hdcMem = CreateCompatibleDC(hdc);
1274 HBITMAP hOrigBitmap;
1275 UINT arrow_bitmap_width, arrow_bitmap_height;
1279 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
1280 arrow_bitmap_width = bmp.bmWidth;
1281 arrow_bitmap_height = bmp.bmHeight;
1284 if (lppop->nScrollPos)
1285 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
1287 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
1290 rect.right = lppop->Width;
1291 rect.bottom = arrow_bitmap_height;
1292 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1293 BitBlt(hdc, (lppop->Width - arrow_bitmap_width) / 2, 0,
1294 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1295 rect.top = lppop->Height - arrow_bitmap_height;
1296 rect.bottom = lppop->Height;
1297 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1298 if (lppop->nScrollPos < lppop->nTotalHeight - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
1299 SelectObject(hdcMem, get_down_arrow_bitmap());
1301 SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
1302 BitBlt(hdc, (lppop->Width - arrow_bitmap_width) / 2,
1303 lppop->Height - arrow_bitmap_height,
1304 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1305 SelectObject(hdcMem, hOrigBitmap);
1310 /***********************************************************************
1313 * Draws the popup-menu arrow.
1315 static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_bitmap_width,
1316 UINT arrow_bitmap_height)
1318 HDC hdcMem = CreateCompatibleDC( hdc );
1319 HBITMAP hOrigBitmap;
1321 hOrigBitmap = SelectObject( hdcMem, get_arrow_bitmap() );
1322 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1323 (rect.top + rect.bottom - arrow_bitmap_height) / 2,
1324 arrow_bitmap_width, arrow_bitmap_height,
1325 hdcMem, 0, 0, SRCCOPY );
1326 SelectObject( hdcMem, hOrigBitmap );
1329 /***********************************************************************
1332 * Draw a single menu item.
1334 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1335 UINT height, BOOL menuBar, UINT odaction )
1338 BOOL flat_menu = FALSE;
1340 UINT arrow_bitmap_width = 0, arrow_bitmap_height = 0;
1341 POPUPMENU *menu = MENU_GetMenu(hmenu);
1344 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1348 GetObjectW( get_arrow_bitmap(), sizeof(bmp), &bmp );
1349 arrow_bitmap_width = bmp.bmWidth;
1350 arrow_bitmap_height = bmp.bmHeight;
1353 if (lpitem->fType & MF_SYSMENU)
1355 if( !IsIconic(hwnd) )
1356 NC_DrawSysButton( hwnd, hdc, lpitem->fState & (MF_HILITE | MF_MOUSESELECT) );
1360 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1361 bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
1365 if (lpitem->fState & MF_HILITE)
1367 if(menuBar && !flat_menu) {
1368 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1369 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1371 if(lpitem->fState & MF_GRAYED)
1372 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1374 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1375 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1380 if (lpitem->fState & MF_GRAYED)
1381 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1383 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1384 SetBkColor( hdc, GetSysColor( bkgnd ) );
1387 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->rect));
1388 rect = lpitem->rect;
1389 MENU_AdjustMenuItemRect(MENU_GetMenu(hmenu), &rect);
1391 if (lpitem->fType & MF_OWNERDRAW)
1394 ** Experimentation under Windows reveals that an owner-drawn
1395 ** menu is given the rectangle which includes the space it requested
1396 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1397 ** and a popup-menu arrow. This is the value of lpitem->rect.
1398 ** Windows will leave all drawing to the application except for
1399 ** the popup-menu arrow. Windows always draws that itself, after
1400 ** the menu owner has finished drawing.
1404 dis.CtlType = ODT_MENU;
1406 dis.itemID = lpitem->wID;
1407 dis.itemData = lpitem->dwItemData;
1409 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1410 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED|ODS_DISABLED;
1411 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1412 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1413 dis.hwndItem = (HWND)hmenu;
1416 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1417 "hwndItem=%p, hdc=%p, rcItem=%s\n", hwndOwner,
1418 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1419 dis.hDC, wine_dbgstr_rect( &dis.rcItem));
1420 SendMessageW( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1421 /* Draw the popup-menu arrow */
1422 if (lpitem->fType & MF_POPUP)
1423 draw_popup_arrow( hdc, rect, arrow_bitmap_width,
1424 arrow_bitmap_height);
1428 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1430 if (lpitem->fState & MF_HILITE)
1434 InflateRect (&rect, -1, -1);
1435 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT));
1436 InflateRect (&rect, 1, 1);
1437 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1442 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1444 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1448 FillRect( hdc, &rect, GetSysColorBrush(bkgnd) );
1450 SetBkMode( hdc, TRANSPARENT );
1452 /* vertical separator */
1453 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1459 rc.bottom = height - 3;
1462 oldPen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_BTNSHADOW) );
1463 MoveToEx( hdc, rc.left, rc.top, NULL );
1464 LineTo( hdc, rc.left, rc.bottom );
1465 SelectObject( hdc, oldPen );
1468 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1471 /* horizontal separator */
1472 if (lpitem->fType & MF_SEPARATOR)
1479 rc.top = ( rc.top + rc.bottom) / 2;
1482 oldPen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_BTNSHADOW) );
1483 MoveToEx( hdc, rc.left, rc.top, NULL );
1484 LineTo( hdc, rc.right, rc.top );
1485 SelectObject( hdc, oldPen );
1488 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1492 /* helper lines for debugging */
1493 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1494 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1495 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1496 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1499 if (lpitem->hbmpItem) {
1500 /* calculate the bitmap rectangle in coordinates relative
1501 * to the item rectangle */
1503 if( lpitem->hbmpItem == HBMMENU_CALLBACK)
1506 bmprc.left = lpitem->text ? menucharsize.cx : 0;
1509 if( !(menu->dwStyle & ( MNS_CHECKORBMP | MNS_NOCHECK)))
1510 bmprc.left += GetSystemMetrics( SM_CXMENUCHECK);
1512 bmprc.right = bmprc.left + lpitem->bmpsize.cx;
1513 if( menuBar && !(lpitem->hbmpItem == HBMMENU_CALLBACK))
1516 bmprc.top = (lpitem->rect.bottom - lpitem->rect.top -
1517 lpitem->bmpsize.cy) / 2;
1518 bmprc.bottom = bmprc.top + lpitem->bmpsize.cy;
1524 INT y = rect.top + rect.bottom;
1526 int checked = FALSE;
1527 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1528 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1529 /* Draw the check mark
1532 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1534 if( !(menu->dwStyle & MNS_NOCHECK)) {
1535 bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit :
1536 lpitem->hUnCheckBit;
1537 if (bm) /* we have a custom bitmap */
1539 HDC hdcMem = CreateCompatibleDC( hdc );
1541 SelectObject( hdcMem, bm );
1542 BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
1543 check_bitmap_width, check_bitmap_height,
1544 hdcMem, 0, 0, SRCCOPY );
1548 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1551 HBITMAP bm = CreateBitmap( check_bitmap_width,
1552 check_bitmap_height, 1, 1, NULL );
1553 HDC hdcMem = CreateCompatibleDC( hdc );
1555 SelectObject( hdcMem, bm );
1556 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
1557 DrawFrameControl( hdcMem, &r, DFC_MENU,
1558 (lpitem->fType & MFT_RADIOCHECK) ?
1559 DFCS_MENUBULLET : DFCS_MENUCHECK );
1560 BitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom,
1561 hdcMem, 0, 0, SRCCOPY );
1567 if( lpitem->hbmpItem &&
1568 !( checked && (menu->dwStyle & MNS_CHECKORBMP))) {
1570 /* some applications make this assumption on the DC's origin */
1571 SetViewportOrgEx( hdc, lpitem->rect.left, lpitem->rect.top, &origorg);
1572 MENU_DrawBitmapItem(hdc, lpitem, &bmprc, hmenu, hwndOwner,
1574 SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1576 /* Draw the popup-menu arrow */
1577 if (lpitem->fType & MF_POPUP)
1578 draw_popup_arrow( hdc, rect, arrow_bitmap_width,
1579 arrow_bitmap_height);
1581 if( !(menu->dwStyle & MNS_NOCHECK))
1582 rect.left += check_bitmap_width;
1583 rect.right -= arrow_bitmap_width;
1585 else if( lpitem->hbmpItem)
1586 { /* Draw the bitmap */
1589 SetViewportOrgEx( hdc, lpitem->rect.left, lpitem->rect.top, &origorg);
1590 MENU_DrawBitmapItem( hdc, lpitem, &bmprc, hmenu, hwndOwner,
1592 SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1594 /* process text if present */
1600 UINT uFormat = (menuBar) ?
1601 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1602 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1604 if( !(menu->dwStyle & MNS_CHECKORBMP))
1605 rect.left += menu->maxBmpSize.cx;
1607 if ( lpitem->fState & MFS_DEFAULT )
1609 hfontOld = SelectObject( hdc, get_menu_font(TRUE) );
1613 if( lpitem->hbmpItem)
1614 rect.left += lpitem->bmpsize.cx;
1615 if( !(lpitem->hbmpItem == HBMMENU_CALLBACK))
1616 rect.left += menucharsize.cx;
1617 rect.right -= menucharsize.cx;
1620 for (i = 0; lpitem->text[i]; i++)
1621 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1624 if(lpitem->fState & MF_GRAYED)
1626 if (!(lpitem->fState & MF_HILITE) )
1628 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1629 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1630 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1631 --rect.left; --rect.top; --rect.right; --rect.bottom;
1633 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1636 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
1638 /* paint the shortcut text */
1639 if (!menuBar && lpitem->text[i]) /* There's a tab or flush-right char */
1641 if (lpitem->text[i] == '\t')
1643 rect.left = lpitem->xTab;
1644 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1648 rect.right = lpitem->xTab;
1649 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1652 if(lpitem->fState & MF_GRAYED)
1654 if (!(lpitem->fState & MF_HILITE) )
1656 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1657 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1658 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1659 --rect.left; --rect.top; --rect.right; --rect.bottom;
1661 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1663 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1667 SelectObject (hdc, hfontOld);
1672 /***********************************************************************
1673 * MENU_DrawPopupMenu
1675 * Paint a popup menu.
1677 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1679 HBRUSH hPrevBrush = 0;
1682 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
1684 GetClientRect( hwnd, &rect );
1686 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1687 && (SelectObject( hdc, get_menu_font(FALSE))))
1691 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1693 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1697 BOOL flat_menu = FALSE;
1699 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1701 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW));
1703 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1705 if( (menu = MENU_GetMenu( hmenu )))
1707 /* draw menu items */
1714 for( u = menu->nItems; u > 0; u--, item++)
1715 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc,
1716 item, menu->Height, FALSE, ODA_DRAWENTIRE );
1718 /* draw scroll arrows */
1719 if (menu->bScrolling)
1720 MENU_DrawScrollArrows(menu, hdc);
1724 SelectObject( hdc, hPrevBrush );
1729 /***********************************************************************
1732 * Paint a menu bar. Returns the height of the menu bar.
1733 * called from [windows/nonclient.c]
1735 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1740 HMENU hMenu = GetMenu(hwnd);
1742 lppop = MENU_GetMenu( hMenu );
1743 if (lppop == NULL || lprect == NULL)
1745 return GetSystemMetrics(SM_CYMENU);
1750 hfontOld = SelectObject( hDC, get_menu_font(FALSE));
1752 if (lppop->Height == 0)
1753 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1755 lprect->bottom = lprect->top + lppop->Height;
1757 if (hfontOld) SelectObject( hDC, hfontOld);
1758 return lppop->Height;
1761 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
1765 /***********************************************************************
1768 * Display a popup menu.
1770 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1771 INT x, INT y, INT xanchor, INT yanchor )
1776 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1777 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1779 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1780 if (menu->FocusedItem != NO_SELECTED_ITEM)
1782 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1783 menu->FocusedItem = NO_SELECTED_ITEM;
1786 /* store the owner for DrawItem */
1787 menu->hwndOwner = hwndOwner;
1789 menu->nScrollPos = 0;
1790 MENU_PopupMenuCalcSize( menu, hwndOwner );
1792 /* adjust popup menu pos so that it fits within the desktop */
1794 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1795 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1797 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1800 x -= width - xanchor;
1801 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1802 x = GetSystemMetrics(SM_CXSCREEN) - width;
1806 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1809 y -= height + yanchor;
1810 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1811 y = GetSystemMetrics(SM_CYSCREEN) - height;
1815 /* NOTE: In Windows, top menu popup is not owned. */
1816 menu->hWnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL,
1817 WS_POPUP, x, y, width, height,
1818 hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
1820 if( !menu->hWnd ) return FALSE;
1821 if (!top_popup) top_popup = menu->hWnd;
1823 /* Display the window */
1825 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1826 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1827 UpdateWindow( menu->hWnd );
1832 /***********************************************************************
1833 * MENU_EnsureMenuItemVisible
1836 MENU_EnsureMenuItemVisible(LPPOPUPMENU lppop, UINT wIndex, HDC hdc)
1838 if (lppop->bScrolling)
1840 MENUITEM *item = &lppop->items[wIndex];
1841 UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
1842 UINT nOldPos = lppop->nScrollPos;
1844 UINT arrow_bitmap_height;
1847 GetClientRect(lppop->hWnd, &rc);
1849 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
1850 arrow_bitmap_height = bmp.bmHeight;
1852 rc.top += arrow_bitmap_height;
1853 rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
1855 nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
1856 if (item->rect.bottom > lppop->nScrollPos + nMaxHeight)
1859 lppop->nScrollPos = item->rect.bottom - nMaxHeight;
1860 ScrollWindow(lppop->hWnd, 0, nOldPos - lppop->nScrollPos, &rc, &rc);
1861 MENU_DrawScrollArrows(lppop, hdc);
1863 else if (item->rect.top - MENU_TOP_MARGIN < lppop->nScrollPos)
1865 lppop->nScrollPos = item->rect.top - MENU_TOP_MARGIN;
1866 ScrollWindow(lppop->hWnd, 0, nOldPos - lppop->nScrollPos, &rc, &rc);
1867 MENU_DrawScrollArrows(lppop, hdc);
1873 /***********************************************************************
1876 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1877 BOOL sendMenuSelect, HMENU topmenu )
1882 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1884 lppop = MENU_GetMenu( hmenu );
1885 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
1887 if (lppop->FocusedItem == wIndex) return;
1888 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1889 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1890 if (!top_popup) top_popup = lppop->hWnd;
1892 SelectObject( hdc, get_menu_font(FALSE));
1894 /* Clear previous highlighted item */
1895 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1897 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1898 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1899 lppop->Height, !(lppop->wFlags & MF_POPUP),
1903 /* Highlight new item (if any) */
1904 lppop->FocusedItem = wIndex;
1905 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1907 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1908 lppop->items[wIndex].fState |= MF_HILITE;
1909 MENU_EnsureMenuItemVisible(lppop, wIndex, hdc);
1910 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1911 &lppop->items[wIndex], lppop->Height,
1912 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1916 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1917 SendMessageW( hwndOwner, WM_MENUSELECT,
1918 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1919 ip->fType | ip->fState |
1920 (lppop->wFlags & MF_SYSMENU)), (LPARAM)hmenu);
1923 else if (sendMenuSelect) {
1926 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1927 POPUPMENU *ptm = MENU_GetMenu( topmenu );
1928 MENUITEM *ip = &ptm->items[pos];
1929 SendMessageW( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1930 ip->fType | ip->fState |
1931 (ptm->wFlags & MF_SYSMENU)), (LPARAM)topmenu);
1935 ReleaseDC( lppop->hWnd, hdc );
1939 /***********************************************************************
1940 * MENU_MoveSelection
1942 * Moves currently selected item according to the offset parameter.
1943 * If there is no selection then it should select the last item if
1944 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1946 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1951 TRACE("hwnd=%p hmenu=%p off=0x%04x\n", hwndOwner, hmenu, offset);
1953 menu = MENU_GetMenu( hmenu );
1954 if ((!menu) || (!menu->items)) return;
1956 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1958 if( menu->nItems == 1 ) return; else
1959 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1961 if (!(menu->items[i].fType & MF_SEPARATOR))
1963 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1968 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1969 i >= 0 && i < menu->nItems ; i += offset)
1970 if (!(menu->items[i].fType & MF_SEPARATOR))
1972 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1978 /**********************************************************************
1981 * Set an item's flags, id and text ptr. Called by InsertMenu() and
1984 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id,
1987 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1988 TRACE("flags=%x str=%p\n", flags, str);
1990 if (IS_STRING_ITEM(flags))
1992 LPWSTR prevText = item->text;
1995 flags |= MF_SEPARATOR;
2001 /* Item beginning with a backspace is a help item */
2007 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
2009 strcpyW( text, str );
2012 item->hbmpItem = NULL;
2013 HeapFree( GetProcessHeap(), 0, prevText );
2015 else if(( flags & MFT_BITMAP)) {
2016 item->hbmpItem = HBITMAP_32(LOWORD(str));
2017 /* setting bitmap clears text */
2018 HeapFree( GetProcessHeap(), 0, item->text );
2022 if (flags & MF_OWNERDRAW)
2023 item->dwItemData = (DWORD_PTR)str;
2025 item->dwItemData = 0;
2027 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != (HMENU)id) )
2028 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
2030 if (flags & MF_POPUP)
2032 POPUPMENU *menu = MENU_GetMenu((HMENU)id);
2033 if (menu) menu->wFlags |= MF_POPUP;
2045 if (flags & MF_POPUP) item->hSubMenu = (HMENU)id;
2047 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
2048 flags |= MF_POPUP; /* keep popup */
2050 item->fType = flags & TYPE_MASK;
2051 item->fState = (flags & STATE_MASK) &
2052 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
2054 /* Don't call SetRectEmpty here! */
2056 debug_print_menuitem("MENU_SetItemData to : ", item, "");
2061 /**********************************************************************
2064 * Insert (allocate) a new item into a menu.
2066 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
2071 if (!(menu = MENU_GetMenu(hMenu)))
2074 /* Find where to insert new item */
2076 if (flags & MF_BYPOSITION) {
2077 if (pos > menu->nItems)
2080 if (!MENU_FindItem( &hMenu, &pos, flags ))
2083 if (!(menu = MENU_GetMenu( hMenu )))
2088 /* Create new items array */
2090 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
2093 WARN("allocation failed\n" );
2096 if (menu->nItems > 0)
2098 /* Copy the old array into the new one */
2099 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
2100 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
2101 (menu->nItems-pos)*sizeof(MENUITEM) );
2102 HeapFree( GetProcessHeap(), 0, menu->items );
2104 menu->items = newItems;
2106 memset( &newItems[pos], 0, sizeof(*newItems) );
2107 menu->Height = 0; /* force size recalculate */
2108 return &newItems[pos];
2112 /**********************************************************************
2113 * MENU_ParseResource
2115 * Parse a standard menu resource and add items to the menu.
2116 * Return a pointer to the end of the resource.
2118 * NOTE: flags is equivalent to the mtOption field
2120 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
2127 flags = GET_WORD(res);
2128 res += sizeof(WORD);
2129 if (!(flags & MF_POPUP))
2132 res += sizeof(WORD);
2135 if (!unicode) res += strlen(str) + 1;
2136 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
2137 if (flags & MF_POPUP)
2139 HMENU hSubMenu = CreatePopupMenu();
2140 if (!hSubMenu) return NULL;
2141 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
2143 if (!unicode) AppendMenuA( hMenu, flags, (UINT_PTR)hSubMenu, str );
2144 else AppendMenuW( hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str );
2146 else /* Not a popup */
2148 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
2149 else AppendMenuW( hMenu, flags, id,
2150 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
2152 } while (!(flags & MF_END));
2157 /**********************************************************************
2158 * MENUEX_ParseResource
2160 * Parse an extended menu resource and add items to the menu.
2161 * Return a pointer to the end of the resource.
2163 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
2169 mii.cbSize = sizeof(mii);
2170 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
2171 mii.fType = GET_DWORD(res);
2172 res += sizeof(DWORD);
2173 mii.fState = GET_DWORD(res);
2174 res += sizeof(DWORD);
2175 mii.wID = GET_DWORD(res);
2176 res += sizeof(DWORD);
2177 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
2178 res += sizeof(WORD);
2179 /* Align the text on a word boundary. */
2180 res += (~((UINT_PTR)res - 1)) & 1;
2181 mii.dwTypeData = (LPWSTR) res;
2182 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2183 /* Align the following fields on a dword boundary. */
2184 res += (~((UINT_PTR)res - 1)) & 3;
2186 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2187 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
2189 if (resinfo & 1) { /* Pop-up? */
2190 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2191 res += sizeof(DWORD);
2192 mii.hSubMenu = CreatePopupMenu();
2195 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2196 DestroyMenu(mii.hSubMenu);
2199 mii.fMask |= MIIM_SUBMENU;
2200 mii.fType |= MF_POPUP;
2202 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
2204 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2205 mii.wID, mii.fType);
2206 mii.fType |= MF_SEPARATOR;
2208 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2209 } while (!(resinfo & MF_END));
2214 /***********************************************************************
2217 * Return the handle of the selected sub-popup menu (if any).
2219 static HMENU MENU_GetSubPopup( HMENU hmenu )
2224 menu = MENU_GetMenu( hmenu );
2226 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2228 item = &menu->items[menu->FocusedItem];
2229 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2230 return item->hSubMenu;
2235 /***********************************************************************
2236 * MENU_HideSubPopups
2238 * Hide the sub-popup menus of this menu.
2240 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2241 BOOL sendMenuSelect )
2243 POPUPMENU *menu = MENU_GetMenu( hmenu );
2245 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2247 if (menu && top_popup)
2253 if (menu->FocusedItem != NO_SELECTED_ITEM)
2255 item = &menu->items[menu->FocusedItem];
2256 if (!(item->fType & MF_POPUP) ||
2257 !(item->fState & MF_MOUSESELECT)) return;
2258 item->fState &= ~MF_MOUSESELECT;
2259 hsubmenu = item->hSubMenu;
2262 submenu = MENU_GetMenu( hsubmenu );
2263 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2264 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2265 DestroyWindow( submenu->hWnd );
2271 /***********************************************************************
2274 * Display the sub-menu of the selected item of this menu.
2275 * Return the handle of the submenu, or hmenu if no submenu to display.
2277 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2278 BOOL selectFirst, UINT wFlags )
2285 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, selectFirst);
2287 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2289 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
2291 item = &menu->items[menu->FocusedItem];
2292 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
2295 /* message must be sent before using item,
2296 because nearly everything may be changed by the application ! */
2298 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2299 if (!(wFlags & TPM_NONOTIFY))
2300 SendMessageW( hwndOwner, WM_INITMENUPOPUP, (WPARAM)item->hSubMenu,
2301 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2303 item = &menu->items[menu->FocusedItem];
2306 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2307 if (!(item->fState & MF_HILITE))
2309 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2310 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2312 SelectObject( hdc, get_menu_font(FALSE));
2314 item->fState |= MF_HILITE;
2315 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2316 ReleaseDC( menu->hWnd, hdc );
2318 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2321 item->fState |= MF_MOUSESELECT;
2323 if (IS_SYSTEM_MENU(menu))
2325 MENU_InitSysMenuPopup(item->hSubMenu,
2326 GetWindowLongW( menu->hWnd, GWL_STYLE ),
2327 GetClassLongW( menu->hWnd, GCL_STYLE));
2329 NC_GetSysPopupPos( menu->hWnd, &rect );
2330 rect.top = rect.bottom;
2331 rect.right = GetSystemMetrics(SM_CXSIZE);
2332 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2336 GetWindowRect( menu->hWnd, &rect );
2337 if (menu->wFlags & MF_POPUP)
2339 RECT rc = item->rect;
2341 MENU_AdjustMenuItemRect(menu, &rc);
2342 rect.left += rc.right - GetSystemMetrics(SM_CXBORDER);
2344 rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER);
2345 rect.bottom = rc.top - rc.bottom;
2349 rect.left += item->rect.left;
2350 rect.top += item->rect.bottom;
2351 rect.right = item->rect.right - item->rect.left;
2352 rect.bottom = item->rect.bottom - item->rect.top;
2356 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2357 rect.left, rect.top, rect.right, rect.bottom );
2359 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2360 return item->hSubMenu;
2365 /**********************************************************************
2368 HWND MENU_IsMenuActive(void)
2373 /***********************************************************************
2376 * Walks menu chain trying to find a menu pt maps to.
2378 static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2380 POPUPMENU *menu = MENU_GetMenu( hMenu );
2381 UINT item = menu->FocusedItem;
2384 /* try subpopup first (if any) */
2385 ret = (item != NO_SELECTED_ITEM &&
2386 (menu->items[item].fType & MF_POPUP) &&
2387 (menu->items[item].fState & MF_MOUSESELECT))
2388 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
2390 if (!ret) /* check the current window (avoiding WM_HITTEST) */
2392 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2393 if( menu->wFlags & MF_POPUP )
2395 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2397 else if (ht == HTSYSMENU)
2398 ret = get_win_sys_menu( menu->hWnd );
2399 else if (ht == HTMENU)
2400 ret = GetMenu( menu->hWnd );
2405 /***********************************************************************
2406 * MENU_ExecFocusedItem
2408 * Execute a menu item (for instance when user pressed Enter).
2409 * Return the wID of the executed item. Otherwise, -1 indicating
2410 * that no menu item was executed;
2411 * Have to receive the flags for the TrackPopupMenu options to avoid
2412 * sending unwanted message.
2415 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2418 POPUPMENU *menu = MENU_GetMenu( hMenu );
2420 TRACE("%p hmenu=%p\n", pmt, hMenu);
2422 if (!menu || !menu->nItems ||
2423 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2425 item = &menu->items[menu->FocusedItem];
2427 TRACE("%p %08x %p\n", hMenu, item->wID, item->hSubMenu);
2429 if (!(item->fType & MF_POPUP))
2431 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2433 /* If TPM_RETURNCMD is set you return the id, but
2434 do not send a message to the owner */
2435 if(!(wFlags & TPM_RETURNCMD))
2437 if( menu->wFlags & MF_SYSMENU )
2438 PostMessageW( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2439 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2441 PostMessageW( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2447 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2452 /***********************************************************************
2453 * MENU_SwitchTracking
2455 * Helper function for menu navigation routines.
2457 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2459 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2460 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2462 TRACE("%p hmenu=%p 0x%04x\n", pmt, hPtMenu, id);
2464 if( pmt->hTopMenu != hPtMenu &&
2465 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2467 /* both are top level menus (system and menu-bar) */
2468 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2469 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2470 pmt->hTopMenu = hPtMenu;
2472 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2473 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2477 /***********************************************************************
2480 * Return TRUE if we can go on with menu tracking.
2482 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2484 TRACE("%p hPtMenu=%p\n", pmt, hPtMenu);
2489 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2492 if( IS_SYSTEM_MENU(ptmenu) )
2493 item = ptmenu->items;
2495 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2499 if( ptmenu->FocusedItem != id )
2500 MENU_SwitchTracking( pmt, hPtMenu, id );
2502 /* If the popup menu is not already "popped" */
2503 if(!(item->fState & MF_MOUSESELECT ))
2505 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2510 /* Else the click was on the menu bar, finish the tracking */
2515 /***********************************************************************
2518 * Return the value of MENU_ExecFocusedItem if
2519 * the selected item was not a popup. Else open the popup.
2520 * A -1 return value indicates that we go on with menu tracking.
2523 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2525 TRACE("%p hmenu=%p\n", pmt, hPtMenu);
2530 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2533 if( IS_SYSTEM_MENU(ptmenu) )
2534 item = ptmenu->items;
2536 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2538 if( item && (ptmenu->FocusedItem == id ))
2540 if( !(item->fType & MF_POPUP) )
2541 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2543 /* If we are dealing with the top-level menu */
2544 /* and this is a click on an already "popped" item: */
2545 /* Stop the menu tracking and close the opened submenus */
2546 if((pmt->hTopMenu == hPtMenu) && ptmenu->bTimeToHide)
2549 ptmenu->bTimeToHide = TRUE;
2555 /***********************************************************************
2558 * Return TRUE if we can go on with menu tracking.
2560 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2562 UINT id = NO_SELECTED_ITEM;
2563 POPUPMENU *ptmenu = NULL;
2567 ptmenu = MENU_GetMenu( hPtMenu );
2568 if( IS_SYSTEM_MENU(ptmenu) )
2571 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2574 if( id == NO_SELECTED_ITEM )
2576 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2577 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2580 else if( ptmenu->FocusedItem != id )
2582 MENU_SwitchTracking( pmt, hPtMenu, id );
2583 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2589 /***********************************************************************
2592 static void MENU_SetCapture( HWND hwnd )
2596 SERVER_START_REQ( set_capture_window )
2599 req->flags = CAPTURE_MENU;
2600 if (!wine_server_call_err( req ))
2602 previous = reply->previous;
2603 hwnd = reply->full_handle;
2608 if (previous && previous != hwnd)
2609 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
2613 /***********************************************************************
2616 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2618 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2620 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2622 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2623 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2625 MDINEXTMENU next_menu;
2630 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2631 next_menu.hmenuNext = 0;
2632 next_menu.hwndNext = 0;
2633 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2635 TRACE("%p [%p] -> %p [%p]\n",
2636 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2638 if (!next_menu.hmenuNext || !next_menu.hwndNext)
2640 DWORD style = GetWindowLongW( pmt->hOwnerWnd, GWL_STYLE );
2641 hNewWnd = pmt->hOwnerWnd;
2642 if( IS_SYSTEM_MENU(menu) )
2644 /* switch to the menu bar */
2646 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2650 menu = MENU_GetMenu( hNewMenu );
2651 id = menu->nItems - 1;
2654 else if (style & WS_SYSMENU )
2656 /* switch to the system menu */
2657 hNewMenu = get_win_sys_menu( hNewWnd );
2661 else /* application returned a new menu to switch to */
2663 hNewMenu = next_menu.hmenuNext;
2664 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2666 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2668 DWORD style = GetWindowLongW( hNewWnd, GWL_STYLE );
2670 if (style & WS_SYSMENU &&
2671 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2673 /* get the real system menu */
2674 hNewMenu = get_win_sys_menu(hNewWnd);
2676 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2678 /* FIXME: Not sure what to do here;
2679 * perhaps try to track hNewMenu as a popup? */
2681 TRACE(" -- got confused.\n");
2688 if( hNewMenu != pmt->hTopMenu )
2690 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2692 if( pmt->hCurrentMenu != pmt->hTopMenu )
2693 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2696 if( hNewWnd != pmt->hOwnerWnd )
2698 pmt->hOwnerWnd = hNewWnd;
2699 MENU_SetCapture( pmt->hOwnerWnd );
2702 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2703 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2710 /***********************************************************************
2713 * The idea is not to show the popup if the next input message is
2714 * going to hide it anyway.
2716 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2720 msg.hwnd = pmt->hOwnerWnd;
2722 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2723 pmt->trackFlags |= TF_SKIPREMOVE;
2728 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2729 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2731 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2732 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2733 if( msg.message == WM_KEYDOWN &&
2734 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2736 pmt->trackFlags |= TF_SUSPENDPOPUP;
2743 /* failures go through this */
2744 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2748 /***********************************************************************
2751 * Handle a VK_ESCAPE key event in a menu.
2753 static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2755 BOOL bEndMenu = TRUE;
2757 if (pmt->hCurrentMenu != pmt->hTopMenu)
2759 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2761 if (menu->wFlags & MF_POPUP)
2763 HMENU hmenutmp, hmenuprev;
2765 hmenuprev = hmenutmp = pmt->hTopMenu;
2767 /* close topmost popup */
2768 while (hmenutmp != pmt->hCurrentMenu)
2770 hmenuprev = hmenutmp;
2771 hmenutmp = MENU_GetSubPopup( hmenuprev );
2774 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2775 pmt->hCurrentMenu = hmenuprev;
2783 /***********************************************************************
2786 * Handle a VK_LEFT key event in a menu.
2788 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2791 HMENU hmenutmp, hmenuprev;
2794 hmenuprev = hmenutmp = pmt->hTopMenu;
2795 menu = MENU_GetMenu( hmenutmp );
2797 /* Try to move 1 column left (if possible) */
2798 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2799 NO_SELECTED_ITEM ) {
2801 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2806 /* close topmost popup */
2807 while (hmenutmp != pmt->hCurrentMenu)
2809 hmenuprev = hmenutmp;
2810 hmenutmp = MENU_GetSubPopup( hmenuprev );
2813 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2814 pmt->hCurrentMenu = hmenuprev;
2816 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2818 /* move menu bar selection if no more popups are left */
2820 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2821 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2823 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2825 /* A sublevel menu was displayed - display the next one
2826 * unless there is another displacement coming up */
2828 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2829 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2830 pmt->hTopMenu, TRUE, wFlags);
2836 /***********************************************************************
2839 * Handle a VK_RIGHT key event in a menu.
2841 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2844 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2847 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2849 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->items[0].text),
2850 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2852 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2854 /* If already displaying a popup, try to display sub-popup */
2856 hmenutmp = pmt->hCurrentMenu;
2857 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2859 /* if subpopup was displayed then we are done */
2860 if (hmenutmp != pmt->hCurrentMenu) return;
2863 /* Check to see if there's another column */
2864 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2865 NO_SELECTED_ITEM ) {
2866 TRACE("Going to %d.\n", nextcol );
2867 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2872 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2874 if( pmt->hCurrentMenu != pmt->hTopMenu )
2876 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2877 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2878 } else hmenutmp = 0;
2880 /* try to move to the next item */
2881 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2882 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2884 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2885 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2886 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2887 pmt->hTopMenu, TRUE, wFlags);
2891 /***********************************************************************
2894 * Menu tracking code.
2896 static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2897 HWND hwnd, const RECT *lprect )
2902 INT executedMenuId = -1;
2904 BOOL enterIdleSent = FALSE;
2907 mt.hCurrentMenu = hmenu;
2908 mt.hTopMenu = hmenu;
2909 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2913 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p %s\n",
2914 hmenu, wFlags, x, y, hwnd, wine_dbgstr_rect( lprect));
2917 if (!(menu = MENU_GetMenu( hmenu )))
2919 WARN("Invalid menu handle %p\n", hmenu);
2920 SetLastError(ERROR_INVALID_MENU_HANDLE);
2924 if (wFlags & TPM_BUTTONDOWN)
2926 /* Get the result in order to start the tracking or not */
2927 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2928 fEndMenu = !fRemove;
2931 if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
2933 MENU_SetCapture( mt.hOwnerWnd );
2937 menu = MENU_GetMenu( mt.hCurrentMenu );
2938 if (!menu) /* sometimes happens if I do a window manager close */
2941 /* we have to keep the message in the queue until it's
2942 * clear that menu loop is not over yet. */
2946 if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
2948 if (!CallMsgFilterW( &msg, MSGF_MENU )) break;
2949 /* remove the message from the queue */
2950 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2956 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2957 enterIdleSent = TRUE;
2958 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2964 /* check if EndMenu() tried to cancel us, by posting this message */
2965 if(msg.message == WM_CANCELMODE)
2967 /* we are now out of the loop */
2970 /* remove the message from the queue */
2971 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2973 /* break out of internal loop, ala ESCAPE */
2977 TranslateMessage( &msg );
2980 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2981 enterIdleSent=FALSE;
2984 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2987 * Use the mouse coordinates in lParam instead of those in the MSG
2988 * struct to properly handle synthetic messages. They are already
2989 * in screen coordinates.
2991 mt.pt.x = (short)LOWORD(msg.lParam);
2992 mt.pt.y = (short)HIWORD(msg.lParam);
2994 /* Find a menu for this mouse event */
2995 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2999 /* no WM_NC... messages in captured state */
3001 case WM_RBUTTONDBLCLK:
3002 case WM_RBUTTONDOWN:
3003 if (!(wFlags & TPM_RIGHTBUTTON)) break;
3005 case WM_LBUTTONDBLCLK:
3006 case WM_LBUTTONDOWN:
3007 /* If the message belongs to the menu, removes it from the queue */
3008 /* Else, end menu tracking */
3009 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
3010 fEndMenu = !fRemove;
3014 if (!(wFlags & TPM_RIGHTBUTTON)) break;
3017 /* Check if a menu was selected by the mouse */
3020 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
3022 /* End the loop if executedMenuId is an item ID */
3023 /* or if the job was done (executedMenuId = 0). */
3024 fEndMenu = fRemove = (executedMenuId != -1);
3026 /* No menu was selected by the mouse */
3027 /* if the function was called by TrackPopupMenu, continue
3028 with the menu tracking. If not, stop it */
3030 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
3035 /* the selected menu item must be changed every time */
3036 /* the mouse moves. */
3039 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
3041 } /* switch(msg.message) - mouse */
3043 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
3045 fRemove = TRUE; /* Keyboard messages are always removed */
3058 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
3059 NO_SELECTED_ITEM, FALSE, 0 );
3060 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
3061 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
3065 case VK_DOWN: /* If on menu bar, pull-down the menu */
3067 menu = MENU_GetMenu( mt.hCurrentMenu );
3068 if (!(menu->wFlags & MF_POPUP))
3069 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
3070 else /* otherwise try to move selection */
3071 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
3072 (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
3076 MENU_KeyLeft( &mt, wFlags );
3080 MENU_KeyRight( &mt, wFlags );
3084 fEndMenu = MENU_KeyEscape(&mt, wFlags);
3090 hi.cbSize = sizeof(HELPINFO);
3091 hi.iContextType = HELPINFO_MENUITEM;
3092 if (menu->FocusedItem == NO_SELECTED_ITEM)
3095 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
3096 hi.hItemHandle = hmenu;
3097 hi.dwContextId = menu->dwContextHelpID;
3098 hi.MousePos = msg.pt;
3099 SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
3106 break; /* WM_KEYDOWN */
3113 if (msg.wParam == '\r' || msg.wParam == ' ')
3115 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3116 fEndMenu = (executedMenuId != -1);
3121 /* Hack to avoid control chars. */
3122 /* We will find a better way real soon... */
3123 if (msg.wParam < 32) break;
3125 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
3126 LOWORD(msg.wParam), FALSE );
3127 if (pos == (UINT)-2) fEndMenu = TRUE;
3128 else if (pos == (UINT)-1) MessageBeep(0);
3131 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
3133 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3134 fEndMenu = (executedMenuId != -1);
3138 } /* switch(msg.message) - kbd */
3142 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
3143 DispatchMessageW( &msg );
3147 if (!fEndMenu) fRemove = TRUE;
3149 /* finally remove message from the queue */
3151 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
3152 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
3153 else mt.trackFlags &= ~TF_SKIPREMOVE;
3156 MENU_SetCapture(0); /* release the capture */
3158 /* If dropdown is still painted and the close box is clicked on
3159 then the menu will be destroyed as part of the DispatchMessage above.
3160 This will then invalidate the menu handle in mt.hTopMenu. We should
3161 check for this first. */
3162 if( IsMenu( mt.hTopMenu ) )
3164 menu = MENU_GetMenu( mt.hTopMenu );
3166 if( IsWindow( mt.hOwnerWnd ) )
3168 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
3170 if (menu && (menu->wFlags & MF_POPUP))
3172 DestroyWindow( menu->hWnd );
3175 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3176 SendMessageW( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
3179 /* Reset the variable for hiding menu */
3180 if( menu ) menu->bTimeToHide = FALSE;
3183 /* The return value is only used by TrackPopupMenu */
3184 if (!(wFlags & TPM_RETURNCMD)) return TRUE;
3185 if (executedMenuId == -1) executedMenuId = 0;
3186 return executedMenuId;
3189 /***********************************************************************
3192 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
3196 TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
3200 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3201 if (!(wFlags & TPM_NONOTIFY))
3202 SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
3204 SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
3206 if (!(wFlags & TPM_NONOTIFY))
3208 SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
3209 /* If an app changed/recreated menu bar entries in WM_INITMENU
3210 * menu sizes will be recalculated once the menu created/shown.
3214 /* This makes the menus of applications built with Delphi work.
3215 * It also enables menus to be displayed in more than one window,
3216 * but there are some bugs left that need to be fixed in this case.
3218 if ((menu = MENU_GetMenu( hMenu ))) menu->hWnd = hWnd;
3222 /***********************************************************************
3225 static BOOL MENU_ExitTracking(HWND hWnd)
3227 TRACE("hwnd=%p\n", hWnd);
3229 SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 );
3235 /***********************************************************************
3236 * MENU_TrackMouseMenuBar
3238 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3240 void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
3242 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
3243 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3245 TRACE("wnd=%p ht=0x%04x %s\n", hWnd, ht, wine_dbgstr_point( &pt));
3249 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
3250 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
3251 MENU_ExitTracking(hWnd);
3256 /***********************************************************************
3257 * MENU_TrackKbdMenuBar
3259 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3261 void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar)
3263 UINT uItem = NO_SELECTED_ITEM;
3265 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3267 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
3269 /* find window that has a menu */
3271 while (!WIN_ALLOWED_MENU(GetWindowLongW( hwnd, GWL_STYLE )))
3272 if (!(hwnd = GetAncestor( hwnd, GA_PARENT ))) return;
3274 /* check if we have to track a system menu */
3276 hTrackMenu = GetMenu( hwnd );
3277 if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' )
3279 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
3280 hTrackMenu = get_win_sys_menu( hwnd );
3282 wParam |= HTSYSMENU; /* prevent item lookup */
3285 if (!IsMenu( hTrackMenu )) return;
3287 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3289 if( wChar && wChar != ' ' )
3291 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) );
3292 if ( uItem >= (UINT)(-2) )
3294 if( uItem == (UINT)(-1) ) MessageBeep(0);
3295 /* schedule end of menu tracking */
3296 wFlags |= TF_ENDMENU;
3301 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3303 if (wParam & HTSYSMENU)
3305 /* prevent sysmenu activation for managed windows on Alt down/up */
3306 if (GetPropA( hwnd, "__wine_x11_managed" ))
3307 wFlags |= TF_ENDMENU; /* schedule end of menu tracking */
3311 if( uItem == NO_SELECTED_ITEM )
3312 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3314 PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3318 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3319 MENU_ExitTracking( hwnd );
3323 /**********************************************************************
3324 * TrackPopupMenu (USER32.@)
3326 * Like the win32 API, the function return the command ID only if the
3327 * flag TPM_RETURNCMD is on.
3330 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3331 INT nReserved, HWND hWnd, const RECT *lpRect )
3335 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3337 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3338 if (!(wFlags & TPM_NONOTIFY))
3339 SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0);
3341 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3342 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3343 MENU_ExitTracking(hWnd);
3348 /**********************************************************************
3349 * TrackPopupMenuEx (USER32.@)
3351 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3352 HWND hWnd, LPTPMPARAMS lpTpm )
3354 FIXME("not fully implemented\n" );
3355 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3356 lpTpm ? &lpTpm->rcExclude : NULL );
3359 /***********************************************************************
3362 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3364 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3366 TRACE("hwnd=%p msg=0x%04x wp=0x%04x lp=0x%08lx\n", hwnd, message, wParam, lParam);
3372 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3373 SetWindowLongPtrW( hwnd, 0, (LONG_PTR)cs->lpCreateParams );
3377 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3378 return MA_NOACTIVATE;
3383 BeginPaint( hwnd, &ps );
3384 MENU_DrawPopupMenu( hwnd, ps.hdc,
3385 (HMENU)GetWindowLongPtrW( hwnd, 0 ) );
3386 EndPaint( hwnd, &ps );
3393 /* zero out global pointer in case resident popup window was destroyed. */
3394 if (hwnd == top_popup) top_popup = 0;
3401 if (!GetWindowLongPtrW( hwnd, 0 )) ERR("no menu to display\n");
3404 SetWindowLongPtrW( hwnd, 0, 0 );
3407 case MM_SETMENUHANDLE:
3408 SetWindowLongPtrW( hwnd, 0, wParam );
3411 case MM_GETMENUHANDLE:
3412 return GetWindowLongPtrW( hwnd, 0 );
3415 return DefWindowProcW( hwnd, message, wParam, lParam );
3421 /***********************************************************************
3422 * MENU_GetMenuBarHeight
3424 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3426 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3427 INT orgX, INT orgY )
3433 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
3435 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3437 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3438 SelectObject( hdc, get_menu_font(FALSE));
3439 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3440 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3441 ReleaseDC( hwnd, hdc );
3442 return lppop->Height;
3446 /*******************************************************************
3447 * ChangeMenuA (USER32.@)
3449 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3450 UINT id, UINT flags )
3452 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3453 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3455 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3456 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3458 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3459 flags & MF_BYPOSITION ? pos : id,
3460 flags & ~MF_REMOVE );
3461 /* Default: MF_INSERT */
3462 return InsertMenuA( hMenu, pos, flags, id, data );
3466 /*******************************************************************
3467 * ChangeMenuW (USER32.@)
3469 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3470 UINT id, UINT flags )
3472 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3473 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3475 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3476 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3478 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3479 flags & MF_BYPOSITION ? pos : id,
3480 flags & ~MF_REMOVE );
3481 /* Default: MF_INSERT */
3482 return InsertMenuW( hMenu, pos, flags, id, data );
3486 /*******************************************************************
3487 * CheckMenuItem (USER32.@)
3489 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3494 TRACE("menu=%p id=%04x flags=%04x\n", hMenu, id, flags );
3495 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3496 ret = item->fState & MF_CHECKED;
3497 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3498 else item->fState &= ~MF_CHECKED;
3503 /**********************************************************************
3504 * EnableMenuItem (USER32.@)
3506 BOOL WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3512 TRACE("(%p, %04x, %04x) !\n", hMenu, wItemID, wFlags);
3514 /* Get the Popupmenu to access the owner menu */
3515 if (!(menu = MENU_GetMenu(hMenu)))
3518 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3521 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3522 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3524 /* If the close item in the system menu change update the close button */
3525 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3527 if (menu->hSysMenuOwner != 0)
3530 POPUPMENU* parentMenu;
3532 /* Get the parent menu to access*/
3533 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3536 /* Refresh the frame to reflect the change */
3537 GetWindowRect(parentMenu->hWnd, &rc);
3538 MapWindowPoints(0, parentMenu->hWnd, (POINT *)&rc, 2);
3540 RedrawWindow(parentMenu->hWnd, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
3548 /*******************************************************************
3549 * GetMenuStringA (USER32.@)
3551 INT WINAPI GetMenuStringA(
3552 HMENU hMenu, /* [in] menuhandle */
3553 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3554 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3555 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3556 UINT wFlags /* [in] MF_ flags */
3560 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3561 if (str && nMaxSiz) str[0] = '\0';
3562 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
3563 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
3566 if (!item->text) return 0;
3567 if (!str || !nMaxSiz) return strlenW(item->text);
3568 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3570 TRACE("returning '%s'\n", str );
3575 /*******************************************************************
3576 * GetMenuStringW (USER32.@)
3578 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3579 LPWSTR str, INT nMaxSiz, UINT wFlags )
3583 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3584 if (str && nMaxSiz) str[0] = '\0';
3585 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
3586 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
3589 if (!str || !nMaxSiz) return item->text ? strlenW(item->text) : 0;
3590 if( !(item->text)) {
3594 lstrcpynW( str, item->text, nMaxSiz );
3595 return strlenW(str);
3599 /**********************************************************************
3600 * HiliteMenuItem (USER32.@)
3602 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3606 TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
3607 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3608 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3609 if (menu->FocusedItem == wItemID) return TRUE;
3610 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3611 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3616 /**********************************************************************
3617 * GetMenuState (USER32.@)
3619 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3622 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, wItemID, wFlags);
3623 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3624 debug_print_menuitem (" item: ", item, "");
3625 if (item->fType & MF_POPUP)
3627 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3628 if (!menu) return -1;
3629 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3633 /* We used to (from way back then) mask the result to 0xff. */
3634 /* I don't know why and it seems wrong as the documented */
3635 /* return flag MF_SEPARATOR is outside that mask. */
3636 return (item->fType | item->fState);
3641 /**********************************************************************
3642 * GetMenuItemCount (USER32.@)
3644 INT WINAPI GetMenuItemCount( HMENU hMenu )
3646 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3647 if (!menu) return -1;
3648 TRACE("(%p) returning %d\n", hMenu, menu->nItems );
3649 return menu->nItems;
3653 /**********************************************************************
3654 * GetMenuItemID (USER32.@)
3656 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3660 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
3661 if (lpmi->fType & MF_POPUP) return -1;
3667 /*******************************************************************
3668 * InsertMenuW (USER32.@)
3670 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3671 UINT_PTR id, LPCWSTR str )
3675 if (IS_STRING_ITEM(flags) && str)
3676 TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3677 hMenu, pos, flags, id, debugstr_w(str) );
3678 else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %p (not a string)\n",
3679 hMenu, pos, flags, id, str );
3681 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3683 if (!(MENU_SetItemData( item, flags, id, str )))
3685 RemoveMenu( hMenu, pos, flags );
3689 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3690 (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
3692 item->hCheckBit = item->hUnCheckBit = 0;
3697 /*******************************************************************
3698 * InsertMenuA (USER32.@)
3700 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3701 UINT_PTR id, LPCSTR str )
3705 if (IS_STRING_ITEM(flags) && str)
3707 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3708 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3711 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3712 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3713 HeapFree( GetProcessHeap(), 0, newstr );
3717 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3721 /*******************************************************************
3722 * AppendMenuA (USER32.@)
3724 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3725 UINT_PTR id, LPCSTR data )
3727 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3731 /*******************************************************************
3732 * AppendMenuW (USER32.@)
3734 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3735 UINT_PTR id, LPCWSTR data )
3737 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3741 /**********************************************************************
3742 * RemoveMenu (USER32.@)
3744 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3749 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3750 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3751 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3755 MENU_FreeItemData( item );
3757 if (--menu->nItems == 0)
3759 HeapFree( GetProcessHeap(), 0, menu->items );
3764 while(nPos < menu->nItems)
3770 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3771 menu->nItems * sizeof(MENUITEM) );
3777 /**********************************************************************
3778 * DeleteMenu (USER32.@)
3780 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3782 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3783 if (!item) return FALSE;
3784 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3785 /* nPos is now the position of the item */
3786 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3791 /*******************************************************************
3792 * ModifyMenuW (USER32.@)
3794 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3795 UINT_PTR id, LPCWSTR str )
3799 if (IS_STRING_ITEM(flags))
3800 TRACE("%p %d %04x %04x %s\n", hMenu, pos, flags, id, debugstr_w(str) );
3802 TRACE("%p %d %04x %04x %p\n", hMenu, pos, flags, id, str );
3804 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3805 MENU_GetMenu(hMenu)->Height = 0; /* force size recalculate */
3806 return MENU_SetItemData( item, flags, id, str );
3810 /*******************************************************************
3811 * ModifyMenuA (USER32.@)
3813 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3814 UINT_PTR id, LPCSTR str )
3818 if (IS_STRING_ITEM(flags) && str)
3820 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3821 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3824 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3825 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3826 HeapFree( GetProcessHeap(), 0, newstr );
3830 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3834 /**********************************************************************
3835 * CreatePopupMenu (USER32.@)
3837 HMENU WINAPI CreatePopupMenu(void)
3842 if (!(hmenu = CreateMenu())) return 0;
3843 menu = MENU_GetMenu( hmenu );
3844 menu->wFlags |= MF_POPUP;
3845 menu->bTimeToHide = FALSE;
3850 /**********************************************************************
3851 * GetMenuCheckMarkDimensions (USER.417)
3852 * GetMenuCheckMarkDimensions (USER32.@)
3854 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3856 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3860 /**********************************************************************
3861 * SetMenuItemBitmaps (USER32.@)
3863 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3864 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3867 TRACE("(%p, %04x, %04x, %p, %p)\n",
3868 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3869 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3871 if (!hNewCheck && !hNewUnCheck)
3873 item->fState &= ~MF_USECHECKBITMAPS;
3875 else /* Install new bitmaps */
3877 item->hCheckBit = hNewCheck;
3878 item->hUnCheckBit = hNewUnCheck;
3879 item->fState |= MF_USECHECKBITMAPS;
3885 /**********************************************************************
3886 * CreateMenu (USER32.@)
3888 HMENU WINAPI CreateMenu(void)
3892 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3893 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3895 ZeroMemory(menu, sizeof(POPUPMENU));
3896 menu->wMagic = MENU_MAGIC;
3897 menu->FocusedItem = NO_SELECTED_ITEM;
3898 menu->bTimeToHide = FALSE;
3900 TRACE("return %p\n", hMenu );
3906 /**********************************************************************
3907 * DestroyMenu (USER32.@)
3909 BOOL WINAPI DestroyMenu( HMENU hMenu )
3911 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3913 TRACE("(%p)\n", hMenu);
3916 if (!lppop) return FALSE;
3918 lppop->wMagic = 0; /* Mark it as destroyed */
3920 /* DestroyMenu should not destroy system menu popup owner */
3921 if ((lppop->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && lppop->hWnd)
3923 DestroyWindow( lppop->hWnd );
3927 if (lppop->items) /* recursively destroy submenus */
3930 MENUITEM *item = lppop->items;
3931 for (i = lppop->nItems; i > 0; i--, item++)
3933 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3934 MENU_FreeItemData( item );
3936 HeapFree( GetProcessHeap(), 0, lppop->items );
3938 USER_HEAP_FREE( hMenu );
3943 /**********************************************************************
3944 * GetSystemMenu (USER32.@)
3946 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3948 WND *wndPtr = WIN_GetPtr( hWnd );
3951 if (wndPtr == WND_DESKTOP) return 0;
3952 if (wndPtr == WND_OTHER_PROCESS)
3954 if (IsWindow( hWnd )) FIXME( "not supported on other process window %p\n", hWnd );
3958 if (wndPtr->hSysMenu && bRevert)
3960 DestroyMenu(wndPtr->hSysMenu);
3961 wndPtr->hSysMenu = 0;
3964 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3965 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, 0 );
3967 if( wndPtr->hSysMenu )
3970 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3972 /* Store the dummy sysmenu handle to facilitate the refresh */
3973 /* of the close button if the SC_CLOSE item change */
3974 menu = MENU_GetMenu(retvalue);
3976 menu->hSysMenuOwner = wndPtr->hSysMenu;
3978 WIN_ReleasePtr( wndPtr );
3980 return bRevert ? 0 : retvalue;
3984 /*******************************************************************
3985 * SetSystemMenu (USER32.@)
3987 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3989 WND *wndPtr = WIN_GetPtr( hwnd );
3991 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
3993 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3994 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3995 WIN_ReleasePtr( wndPtr );
4002 /**********************************************************************
4003 * GetMenu (USER32.@)
4005 HMENU WINAPI GetMenu( HWND hWnd )
4007 HMENU retvalue = (HMENU)GetWindowLongPtrW( hWnd, GWLP_ID );
4008 TRACE("for %p returning %p\n", hWnd, retvalue);
4012 /**********************************************************************
4013 * GetMenuBarInfo (USER32.@)
4015 BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi )
4017 FIXME( "(%p,0x%08lx,0x%08lx,%p)\n", hwnd, idObject, idItem, pmbi );
4021 /**********************************************************************
4024 * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
4025 * SetWindowPos call that would result if SetMenu were called directly.
4027 BOOL MENU_SetMenu( HWND hWnd, HMENU hMenu )
4029 TRACE("(%p, %p);\n", hWnd, hMenu);
4031 if (hMenu && !IsMenu(hMenu))
4033 WARN("hMenu %p is not a menu handle\n", hMenu);
4034 SetLastError(ERROR_INVALID_MENU_HANDLE);
4037 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
4040 hWnd = WIN_GetFullHandle( hWnd );
4041 if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */
4047 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
4049 lpmenu->hWnd = hWnd;
4050 lpmenu->Height = 0; /* Make sure we recalculate the size */
4052 SetWindowLongPtrW( hWnd, GWLP_ID, (LONG_PTR)hMenu );
4057 /**********************************************************************
4058 * SetMenu (USER32.@)
4060 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4062 if(!MENU_SetMenu(hWnd, hMenu))
4065 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4066 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4071 /**********************************************************************
4072 * GetSubMenu (USER32.@)
4074 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4078 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return 0;
4079 if (!(lpmi->fType & MF_POPUP)) return 0;
4080 return lpmi->hSubMenu;
4084 /**********************************************************************
4085 * DrawMenuBar (USER32.@)
4087 BOOL WINAPI DrawMenuBar( HWND hWnd )
4090 HMENU hMenu = GetMenu(hWnd);
4092 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
4094 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4096 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4097 lppop->hwndOwner = hWnd;
4098 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4099 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4103 /***********************************************************************
4104 * DrawMenuBarTemp (USER32.@)
4108 * called by W98SE desk.cpl Control Panel Applet
4110 * Not 100% sure about the param names, but close.
4112 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont)
4117 BOOL flat_menu = FALSE;
4119 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
4122 hMenu = GetMenu(hwnd);
4125 hFont = get_menu_font(FALSE);
4127 lppop = MENU_GetMenu( hMenu );
4128 if (lppop == NULL || lprect == NULL)
4130 retvalue = GetSystemMetrics(SM_CYMENU);
4134 TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont);
4136 hfontOld = SelectObject( hDC, hFont);
4138 if (lppop->Height == 0)
4139 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
4141 lprect->bottom = lprect->top + lppop->Height;
4143 FillRect(hDC, lprect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU) );
4145 SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE));
4146 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
4147 LineTo( hDC, lprect->right, lprect->bottom );
4149 if (lppop->nItems == 0)
4151 retvalue = GetSystemMetrics(SM_CYMENU);
4155 for (i = 0; i < lppop->nItems; i++)
4157 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
4158 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
4160 retvalue = lppop->Height;
4163 if (hfontOld) SelectObject (hDC, hfontOld);
4167 /***********************************************************************
4168 * EndMenu (USER.187)
4169 * EndMenu (USER32.@)
4171 void WINAPI EndMenu(void)
4173 /* if we are in the menu code, and it is active */
4174 if (!fEndMenu && top_popup)
4176 /* terminate the menu handling code */
4179 /* needs to be posted to wakeup the internal menu handler */
4180 /* which will now terminate the menu, in the event that */
4181 /* the main window was minimized, or lost focus, so we */
4182 /* don't end up with an orphaned menu */
4183 PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
4188 /***********************************************************************
4189 * LookupMenuHandle (USER.217)
4191 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4193 HMENU hmenu32 = HMENU_32(hmenu);
4195 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4196 else return HMENU_16(hmenu32);
4200 /**********************************************************************
4201 * LoadMenu (USER.150)
4203 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4209 if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4210 if (!name) return 0;
4212 instance = GetExePtr( instance );
4213 if (!(hRsrc = FindResource16( instance, name, (LPSTR)RT_MENU ))) return 0;
4214 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4215 hMenu = LoadMenuIndirect16(LockResource16(handle));
4216 FreeResource16( handle );
4221 /*****************************************************************
4222 * LoadMenuA (USER32.@)
4224 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4226 HRSRC hrsrc = FindResourceA( instance, name, (LPSTR)RT_MENU );
4227 if (!hrsrc) return 0;
4228 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4232 /*****************************************************************
4233 * LoadMenuW (USER32.@)
4235 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4237 HRSRC hrsrc = FindResourceW( instance, name, (LPWSTR)RT_MENU );
4238 if (!hrsrc) return 0;
4239 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4243 /**********************************************************************
4244 * LoadMenuIndirect (USER.220)
4246 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4249 WORD version, offset;
4250 LPCSTR p = (LPCSTR)template;
4252 TRACE("(%p)\n", template );
4253 version = GET_WORD(p);
4257 WARN("version must be 0 for Win16\n" );
4260 offset = GET_WORD(p);
4261 p += sizeof(WORD) + offset;
4262 if (!(hMenu = CreateMenu())) return 0;
4263 if (!MENU_ParseResource( p, hMenu, FALSE ))
4265 DestroyMenu( hMenu );
4268 return HMENU_16(hMenu);
4272 /**********************************************************************
4273 * LoadMenuIndirectW (USER32.@)
4275 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4278 WORD version, offset;
4279 LPCSTR p = (LPCSTR)template;
4281 version = GET_WORD(p);
4283 TRACE("%p, ver %d\n", template, version );
4286 case 0: /* standard format is version of 0 */
4287 offset = GET_WORD(p);
4288 p += sizeof(WORD) + offset;
4289 if (!(hMenu = CreateMenu())) return 0;
4290 if (!MENU_ParseResource( p, hMenu, TRUE ))
4292 DestroyMenu( hMenu );
4296 case 1: /* extended format is version of 1 */
4297 offset = GET_WORD(p);
4298 p += sizeof(WORD) + offset;
4299 if (!(hMenu = CreateMenu())) return 0;
4300 if (!MENUEX_ParseResource( p, hMenu))
4302 DestroyMenu( hMenu );
4307 ERR("version %d not supported.\n", version);
4313 /**********************************************************************
4314 * LoadMenuIndirectA (USER32.@)
4316 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4318 return LoadMenuIndirectW( template );
4322 /**********************************************************************
4325 BOOL WINAPI IsMenu(HMENU hmenu)
4327 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4328 return menu != NULL;
4331 /**********************************************************************
4332 * GetMenuItemInfo_common
4335 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4336 LPMENUITEMINFOW lpmii, BOOL unicode)
4338 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4340 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4345 if( lpmii->fMask & MIIM_TYPE) {
4346 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4347 WARN("invalid combination of fMask bits used\n");
4348 /* this does not happen on Win9x/ME */
4349 SetLastError( ERROR_INVALID_PARAMETER);
4352 lpmii->fType = menu->fType & ~MF_POPUP;
4353 if( menu->hbmpItem) lpmii->fType |= MFT_BITMAP;
4354 lpmii->hbmpItem = menu->hbmpItem; /* not on Win9x/ME */
4355 if( lpmii->fType & MFT_BITMAP) {
4356 lpmii->dwTypeData = (LPWSTR) menu->hbmpItem;
4358 } else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR)) {
4359 /* this does not happen on Win9x/ME */
4360 lpmii->dwTypeData = 0;
4365 /* copy the text string */
4366 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING))) {
4368 if(lpmii->dwTypeData && lpmii->cch) {
4371 *((WCHAR *)lpmii->dwTypeData) = 0;
4373 *((CHAR *)lpmii->dwTypeData) = 0;
4379 len = strlenW(menu->text);
4380 if(lpmii->dwTypeData && lpmii->cch)
4381 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4385 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL,
4386 0, NULL, NULL ) - 1;
4387 if(lpmii->dwTypeData && lpmii->cch)
4388 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4389 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4390 ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
4392 /* if we've copied a substring we return its length */
4393 if(lpmii->dwTypeData && lpmii->cch)
4394 if (lpmii->cch <= len + 1)
4399 /* return length of string */
4400 /* not on Win9x/ME if fType & MFT_BITMAP */
4406 if (lpmii->fMask & MIIM_FTYPE)
4407 lpmii->fType = menu->fType & ~MF_POPUP;
4409 if (lpmii->fMask & MIIM_BITMAP)
4410 lpmii->hbmpItem = menu->hbmpItem;
4412 if (lpmii->fMask & MIIM_STATE)
4413 lpmii->fState = menu->fState;
4415 if (lpmii->fMask & MIIM_ID)
4416 lpmii->wID = menu->wID;
4418 if (lpmii->fMask & MIIM_SUBMENU)
4419 lpmii->hSubMenu = menu->hSubMenu;
4421 /* hSubMenu is always cleared
4422 * (not on Win9x/ME ) */
4423 lpmii->hSubMenu = 0;
4426 if (lpmii->fMask & MIIM_CHECKMARKS) {
4427 lpmii->hbmpChecked = menu->hCheckBit;
4428 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4430 if (lpmii->fMask & MIIM_DATA)
4431 lpmii->dwItemData = menu->dwItemData;
4436 /**********************************************************************
4437 * GetMenuItemInfoA (USER32.@)
4439 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4440 LPMENUITEMINFOA lpmii)
4444 if( lpmii->cbSize != sizeof( mii) &&
4445 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4446 SetLastError( ERROR_INVALID_PARAMETER);
4449 memcpy( &mii, lpmii, lpmii->cbSize);
4450 mii.cbSize = sizeof( mii);
4451 ret = GetMenuItemInfo_common (hmenu, item, bypos,
4452 (LPMENUITEMINFOW)&mii, FALSE);
4453 mii.cbSize = lpmii->cbSize;
4454 memcpy( lpmii, &mii, mii.cbSize);
4458 /**********************************************************************
4459 * GetMenuItemInfoW (USER32.@)
4461 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4462 LPMENUITEMINFOW lpmii)
4466 if( lpmii->cbSize != sizeof( mii) &&
4467 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4468 SetLastError( ERROR_INVALID_PARAMETER);
4471 memcpy( &mii, lpmii, lpmii->cbSize);
4472 mii.cbSize = sizeof( mii);
4473 ret = GetMenuItemInfo_common (hmenu, item, bypos, &mii, TRUE);
4474 mii.cbSize = lpmii->cbSize;
4475 memcpy( lpmii, &mii, mii.cbSize);
4480 /* set a menu item text from a ASCII or Unicode string */
4481 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4487 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4488 strcpyW( menu->text, text );
4492 LPCSTR str = (LPCSTR)text;
4493 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4494 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4495 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4500 /**********************************************************************
4501 * SetMenuItemInfo_common
4504 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4505 const MENUITEMINFOW *lpmii,
4508 if (!menu) return FALSE;
4510 debug_print_menuitem("SetmenuItemInfo_common from: ", menu, "");
4512 if (lpmii->fMask & MIIM_TYPE ) {
4513 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4514 WARN("invalid combination of fMask bits used\n");
4515 /* this does not happen on Win9x/ME */
4516 SetLastError( ERROR_INVALID_PARAMETER);
4519 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4520 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4521 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4523 if (IS_STRING_ITEM(menu->fType)) {
4524 HeapFree(GetProcessHeap(), 0, menu->text);
4525 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4526 } else if( (menu->fType) & MFT_BITMAP)
4527 menu->hbmpItem = (HBITMAP)lpmii->dwTypeData;
4530 if (lpmii->fMask & MIIM_FTYPE ) {
4531 if(( lpmii->fType & MFT_BITMAP)) {
4532 SetLastError( ERROR_INVALID_PARAMETER);
4535 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4536 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4538 if (lpmii->fMask & MIIM_STRING ) {
4539 /* free the string when used */
4540 HeapFree(GetProcessHeap(), 0, menu->text);
4541 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4544 if (lpmii->fMask & MIIM_STATE)
4546 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4547 menu->fState = lpmii->fState;
4550 if (lpmii->fMask & MIIM_ID)
4551 menu->wID = lpmii->wID;
4553 if (lpmii->fMask & MIIM_SUBMENU) {
4554 menu->hSubMenu = lpmii->hSubMenu;
4555 if (menu->hSubMenu) {
4556 POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
4558 subMenu->wFlags |= MF_POPUP;
4559 menu->fType |= MF_POPUP;
4562 SetLastError( ERROR_INVALID_PARAMETER);
4567 menu->fType &= ~MF_POPUP;
4570 if (lpmii->fMask & MIIM_CHECKMARKS)
4572 if (lpmii->fType & MFT_RADIOCHECK)
4573 menu->fType |= MFT_RADIOCHECK;
4575 menu->hCheckBit = lpmii->hbmpChecked;
4576 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4578 if (lpmii->fMask & MIIM_DATA)
4579 menu->dwItemData = lpmii->dwItemData;
4581 if (lpmii->fMask & MIIM_BITMAP)
4582 menu->hbmpItem = lpmii->hbmpItem;
4584 if( !menu->text && !(menu->fType & MFT_OWNERDRAW) && !menu->hbmpItem)
4585 menu->fType |= MFT_SEPARATOR;
4587 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4591 /**********************************************************************
4592 * SetMenuItemInfoA (USER32.@)
4594 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4595 const MENUITEMINFOA *lpmii)
4598 if( lpmii->cbSize != sizeof( mii) &&
4599 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4600 SetLastError( ERROR_INVALID_PARAMETER);
4603 memcpy( &mii, lpmii, lpmii->cbSize);
4604 if( lpmii->cbSize != sizeof( mii)) {
4605 mii.cbSize = sizeof( mii);
4606 mii.hbmpItem = NULL;
4608 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4609 (const MENUITEMINFOW *)&mii, FALSE);
4612 /**********************************************************************
4613 * SetMenuItemInfoW (USER32.@)
4615 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4616 const MENUITEMINFOW *lpmii)
4619 if( lpmii->cbSize != sizeof( mii) &&
4620 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4621 SetLastError( ERROR_INVALID_PARAMETER);
4624 memcpy( &mii, lpmii, lpmii->cbSize);
4625 if( lpmii->cbSize != sizeof( mii)) {
4626 mii.cbSize = sizeof( mii);
4627 mii.hbmpItem = NULL;
4629 return SetMenuItemInfo_common(MENU_FindItem(&hmenu,
4630 &item, bypos? MF_BYPOSITION : 0), &mii, TRUE);
4633 /**********************************************************************
4634 * SetMenuDefaultItem (USER32.@)
4637 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4643 TRACE("(%p,%d,%d)\n", hmenu, uItem, bypos);
4645 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4647 /* reset all default-item flags */
4649 for (i = 0; i < menu->nItems; i++, item++)
4651 item->fState &= ~MFS_DEFAULT;
4654 /* no default item */
4663 if ( uItem >= menu->nItems ) return FALSE;
4664 item[uItem].fState |= MFS_DEFAULT;
4669 for (i = 0; i < menu->nItems; i++, item++)
4671 if (item->wID == uItem)
4673 item->fState |= MFS_DEFAULT;
4682 /**********************************************************************
4683 * GetMenuDefaultItem (USER32.@)
4685 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4691 TRACE("(%p,%d,%d)\n", hmenu, bypos, flags);
4693 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4695 /* find default item */
4699 if (! item) return -1;
4701 while ( !( item->fState & MFS_DEFAULT ) )
4704 if (i >= menu->nItems ) return -1;
4707 /* default: don't return disabled items */
4708 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4710 /* search rekursiv when needed */
4711 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4714 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4715 if ( -1 != ret ) return ret;
4717 /* when item not found in submenu, return the popup item */
4719 return ( bypos ) ? i : item->wID;
4724 /**********************************************************************
4725 * InsertMenuItemA (USER32.@)
4727 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4728 const MENUITEMINFOA *lpmii)
4730 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4732 if( lpmii->cbSize != sizeof( mii) &&
4733 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4734 SetLastError( ERROR_INVALID_PARAMETER);
4737 memcpy( &mii, lpmii, lpmii->cbSize);
4738 if( lpmii->cbSize != sizeof( mii)) {
4739 mii.cbSize = sizeof( mii);
4740 mii.hbmpItem = NULL;
4742 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)&mii, FALSE);
4746 /**********************************************************************
4747 * InsertMenuItemW (USER32.@)
4749 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4750 const MENUITEMINFOW *lpmii)
4752 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4754 if( lpmii->cbSize != sizeof( mii) &&
4755 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4756 SetLastError( ERROR_INVALID_PARAMETER);
4759 memcpy( &mii, lpmii, lpmii->cbSize);
4760 if( lpmii->cbSize != sizeof( mii)) {
4761 mii.cbSize = sizeof( mii);
4762 mii.hbmpItem = NULL;
4764 return SetMenuItemInfo_common(item, &mii, TRUE);
4767 /**********************************************************************
4768 * CheckMenuRadioItem (USER32.@)
4771 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4772 UINT first, UINT last, UINT check,
4775 MENUITEM *mifirst, *milast, *micheck;
4776 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4778 TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos);
4780 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4781 milast = MENU_FindItem (&mlast, &last, bypos);
4782 micheck = MENU_FindItem (&mcheck, &check, bypos);
4784 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4785 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4786 micheck > milast || micheck < mifirst)
4789 while (mifirst <= milast)
4791 if (mifirst == micheck)
4793 mifirst->fType |= MFT_RADIOCHECK;
4794 mifirst->fState |= MFS_CHECKED;
4796 mifirst->fType &= ~MFT_RADIOCHECK;
4797 mifirst->fState &= ~MFS_CHECKED;
4806 /**********************************************************************
4807 * GetMenuItemRect (USER32.@)
4809 * ATTENTION: Here, the returned values in rect are the screen
4810 * coordinates of the item just like if the menu was
4811 * always on the upper left side of the application.
4814 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4817 POPUPMENU *itemMenu;
4821 TRACE("(%p,%p,%d,%p)\n", hwnd, hMenu, uItem, rect);
4823 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4824 referenceHwnd = hwnd;
4828 itemMenu = MENU_GetMenu(hMenu);
4829 if (itemMenu == NULL)
4832 if(itemMenu->hWnd == 0)
4834 referenceHwnd = itemMenu->hWnd;
4837 if ((rect == NULL) || (item == NULL))
4842 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4848 /**********************************************************************
4849 * SetMenuInfo (USER32.@)
4852 * MIM_APPLYTOSUBMENUS
4853 * actually use the items to draw the menu
4855 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4859 TRACE("(%p %p)\n", hMenu, lpmi);
4861 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4864 if (lpmi->fMask & MIM_BACKGROUND)
4865 menu->hbrBack = lpmi->hbrBack;
4867 if (lpmi->fMask & MIM_HELPID)
4868 menu->dwContextHelpID = lpmi->dwContextHelpID;
4870 if (lpmi->fMask & MIM_MAXHEIGHT)
4871 menu->cyMax = lpmi->cyMax;
4873 if (lpmi->fMask & MIM_MENUDATA)
4874 menu->dwMenuData = lpmi->dwMenuData;
4876 if (lpmi->fMask & MIM_STYLE)
4878 menu->dwStyle = lpmi->dwStyle;
4879 if (menu->dwStyle & MNS_AUTODISMISS) FIXME("MNS_AUTODISMISS unimplemented\n");
4880 if (menu->dwStyle & MNS_DRAGDROP) FIXME("MNS_DRAGDROP unimplemented\n");
4881 if (menu->dwStyle & MNS_MODELESS) FIXME("MNS_MODELESS unimplemented\n");
4882 if (menu->dwStyle & MNS_NOTIFYBYPOS) FIXME("MNS_NOTIFYBYPOS unimplemented\n");
4890 /**********************************************************************
4891 * GetMenuInfo (USER32.@)
4897 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4900 TRACE("(%p %p)\n", hMenu, lpmi);
4902 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4905 if (lpmi->fMask & MIM_BACKGROUND)
4906 lpmi->hbrBack = menu->hbrBack;
4908 if (lpmi->fMask & MIM_HELPID)
4909 lpmi->dwContextHelpID = menu->dwContextHelpID;
4911 if (lpmi->fMask & MIM_MAXHEIGHT)
4912 lpmi->cyMax = menu->cyMax;
4914 if (lpmi->fMask & MIM_MENUDATA)
4915 lpmi->dwMenuData = menu->dwMenuData;
4917 if (lpmi->fMask & MIM_STYLE)
4918 lpmi->dwStyle = menu->dwStyle;
4926 /**********************************************************************
4927 * SetMenuContextHelpId (USER32.@)
4929 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4933 TRACE("(%p 0x%08lx)\n", hMenu, dwContextHelpID);
4935 if ((menu = MENU_GetMenu(hMenu)))
4937 menu->dwContextHelpID = dwContextHelpID;
4944 /**********************************************************************
4945 * GetMenuContextHelpId (USER32.@)
4947 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4951 TRACE("(%p)\n", hMenu);
4953 if ((menu = MENU_GetMenu(hMenu)))
4955 return menu->dwContextHelpID;
4960 /**********************************************************************
4961 * MenuItemFromPoint (USER32.@)
4963 INT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4965 POPUPMENU *menu = MENU_GetMenu(hMenu);
4968 /*FIXME: Do we have to handle hWnd here? */
4969 if (!menu) return -1;
4970 if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
4975 /**********************************************************************
4976 * translate_accelerator
4978 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4979 BYTE fVirt, WORD key, WORD cmd )
4984 if (wParam != key) return FALSE;
4986 if (GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4987 if (GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4988 if (GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4990 if (message == WM_CHAR || message == WM_SYSCHAR)
4992 if ( !(fVirt & FVIRTKEY) && (mask & FALT) == (fVirt & FALT) )
4994 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
5000 if(fVirt & FVIRTKEY)
5002 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
5003 wParam, 0xff & HIWORD(lParam));
5005 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
5006 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
5010 if (!(lParam & 0x01000000)) /* no special_key */
5012 if ((fVirt & FALT) && (lParam & 0x20000000))
5013 { /* ^^ ALT pressed */
5014 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
5023 if (message == WM_KEYUP || message == WM_SYSKEYUP)
5027 HMENU hMenu, hSubMenu, hSysMenu;
5028 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
5030 hMenu = (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
5031 hSysMenu = get_win_sys_menu( hWnd );
5033 /* find menu item and ask application to initialize it */
5034 /* 1. in the system menu */
5035 hSubMenu = hSysMenu;
5037 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5041 if (!IsWindowEnabled(hWnd))
5045 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
5046 if(hSubMenu != hSysMenu)
5048 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
5049 TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
5050 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
5052 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
5055 else /* 2. in the window's menu */
5059 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5063 if (!IsWindowEnabled(hWnd))
5067 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
5068 if(hSubMenu != hMenu)
5070 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
5071 TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
5072 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
5074 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
5081 if (uSysStat != (UINT)-1)
5083 if (uSysStat & (MF_DISABLED|MF_GRAYED))
5090 if (uStat != (UINT)-1)
5096 if (uStat & (MF_DISABLED|MF_GRAYED))
5108 if( mesg==WM_COMMAND )
5110 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
5111 SendMessageW(hWnd, mesg, 0x10000 | cmd, 0L);
5113 else if( mesg==WM_SYSCOMMAND )
5115 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
5116 SendMessageW(hWnd, mesg, cmd, 0x00010000L);
5120 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5121 * #0: unknown (please report!)
5122 * #1: for WM_KEYUP,WM_SYSKEYUP
5123 * #2: mouse is captured
5124 * #3: window is disabled
5125 * #4: it's a disabled system menu option
5126 * #5: it's a menu option, but window is iconic
5127 * #6: it's a menu option, but disabled
5129 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
5131 ERR_(accel)(" unknown reason - please report!\n");
5136 /**********************************************************************
5137 * TranslateAcceleratorA (USER32.@)
5138 * TranslateAccelerator (USER32.@)
5140 INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg )
5143 LPACCEL16 lpAccelTbl;
5147 if (!hWnd || !msg) return 0;
5149 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5151 WARN_(accel)("invalid accel handle=%p\n", hAccel);
5155 wParam = msg->wParam;
5157 switch (msg->message)
5166 char ch = LOWORD(wParam);
5168 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
5169 wParam = MAKEWPARAM(wch, HIWORD(wParam));
5177 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
5178 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5182 if (translate_accelerator( hWnd, msg->message, wParam, msg->lParam,
5183 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5185 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5190 /**********************************************************************
5191 * TranslateAcceleratorW (USER32.@)
5193 INT WINAPI TranslateAcceleratorW( HWND hWnd, HACCEL hAccel, LPMSG msg )
5196 LPACCEL16 lpAccelTbl;
5199 if (!hWnd || !msg) return 0;
5201 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5203 WARN_(accel)("invalid accel handle=%p\n", hAccel);
5207 switch (msg->message)
5219 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
5220 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5224 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5225 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5227 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);