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, -2 if a popup is shown;
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 );
2448 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2455 /***********************************************************************
2456 * MENU_SwitchTracking
2458 * Helper function for menu navigation routines.
2460 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2462 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2463 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2465 TRACE("%p hmenu=%p 0x%04x\n", pmt, hPtMenu, id);
2467 if( pmt->hTopMenu != hPtMenu &&
2468 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2470 /* both are top level menus (system and menu-bar) */
2471 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2472 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2473 pmt->hTopMenu = hPtMenu;
2475 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2476 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2480 /***********************************************************************
2483 * Return TRUE if we can go on with menu tracking.
2485 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2487 TRACE("%p hPtMenu=%p\n", pmt, hPtMenu);
2492 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2495 if( IS_SYSTEM_MENU(ptmenu) )
2496 item = ptmenu->items;
2498 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2502 if( ptmenu->FocusedItem != id )
2503 MENU_SwitchTracking( pmt, hPtMenu, id );
2505 /* If the popup menu is not already "popped" */
2506 if(!(item->fState & MF_MOUSESELECT ))
2508 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2513 /* Else the click was on the menu bar, finish the tracking */
2518 /***********************************************************************
2521 * Return the value of MENU_ExecFocusedItem if
2522 * the selected item was not a popup. Else open the popup.
2523 * A -1 return value indicates that we go on with menu tracking.
2526 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2528 TRACE("%p hmenu=%p\n", pmt, hPtMenu);
2533 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2536 if( IS_SYSTEM_MENU(ptmenu) )
2537 item = ptmenu->items;
2539 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2541 if( item && (ptmenu->FocusedItem == id ))
2543 if( !(item->fType & MF_POPUP) )
2545 INT executedMenuId = MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2546 return (executedMenuId < 0) ? -1 : executedMenuId;
2549 /* If we are dealing with the top-level menu */
2550 /* and this is a click on an already "popped" item: */
2551 /* Stop the menu tracking and close the opened submenus */
2552 if((pmt->hTopMenu == hPtMenu) && ptmenu->bTimeToHide)
2555 ptmenu->bTimeToHide = TRUE;
2561 /***********************************************************************
2564 * Return TRUE if we can go on with menu tracking.
2566 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2568 UINT id = NO_SELECTED_ITEM;
2569 POPUPMENU *ptmenu = NULL;
2573 ptmenu = MENU_GetMenu( hPtMenu );
2574 if( IS_SYSTEM_MENU(ptmenu) )
2577 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2580 if( id == NO_SELECTED_ITEM )
2582 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2583 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2586 else if( ptmenu->FocusedItem != id )
2588 MENU_SwitchTracking( pmt, hPtMenu, id );
2589 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2595 /***********************************************************************
2598 static void MENU_SetCapture( HWND hwnd )
2602 SERVER_START_REQ( set_capture_window )
2605 req->flags = CAPTURE_MENU;
2606 if (!wine_server_call_err( req ))
2608 previous = reply->previous;
2609 hwnd = reply->full_handle;
2614 if (previous && previous != hwnd)
2615 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
2619 /***********************************************************************
2622 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2624 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2626 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2628 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2629 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2631 MDINEXTMENU next_menu;
2636 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2637 next_menu.hmenuNext = 0;
2638 next_menu.hwndNext = 0;
2639 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2641 TRACE("%p [%p] -> %p [%p]\n",
2642 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2644 if (!next_menu.hmenuNext || !next_menu.hwndNext)
2646 DWORD style = GetWindowLongW( pmt->hOwnerWnd, GWL_STYLE );
2647 hNewWnd = pmt->hOwnerWnd;
2648 if( IS_SYSTEM_MENU(menu) )
2650 /* switch to the menu bar */
2652 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2656 menu = MENU_GetMenu( hNewMenu );
2657 id = menu->nItems - 1;
2660 else if (style & WS_SYSMENU )
2662 /* switch to the system menu */
2663 hNewMenu = get_win_sys_menu( hNewWnd );
2667 else /* application returned a new menu to switch to */
2669 hNewMenu = next_menu.hmenuNext;
2670 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2672 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2674 DWORD style = GetWindowLongW( hNewWnd, GWL_STYLE );
2676 if (style & WS_SYSMENU &&
2677 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2679 /* get the real system menu */
2680 hNewMenu = get_win_sys_menu(hNewWnd);
2682 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2684 /* FIXME: Not sure what to do here;
2685 * perhaps try to track hNewMenu as a popup? */
2687 TRACE(" -- got confused.\n");
2694 if( hNewMenu != pmt->hTopMenu )
2696 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2698 if( pmt->hCurrentMenu != pmt->hTopMenu )
2699 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2702 if( hNewWnd != pmt->hOwnerWnd )
2704 pmt->hOwnerWnd = hNewWnd;
2705 MENU_SetCapture( pmt->hOwnerWnd );
2708 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2709 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2716 /***********************************************************************
2719 * The idea is not to show the popup if the next input message is
2720 * going to hide it anyway.
2722 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2726 msg.hwnd = pmt->hOwnerWnd;
2728 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2729 pmt->trackFlags |= TF_SKIPREMOVE;
2734 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2735 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2737 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2738 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2739 if( msg.message == WM_KEYDOWN &&
2740 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2742 pmt->trackFlags |= TF_SUSPENDPOPUP;
2749 /* failures go through this */
2750 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2754 /***********************************************************************
2757 * Handle a VK_ESCAPE key event in a menu.
2759 static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2761 BOOL bEndMenu = TRUE;
2763 if (pmt->hCurrentMenu != pmt->hTopMenu)
2765 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2767 if (menu->wFlags & MF_POPUP)
2769 HMENU hmenutmp, hmenuprev;
2771 hmenuprev = hmenutmp = pmt->hTopMenu;
2773 /* close topmost popup */
2774 while (hmenutmp != pmt->hCurrentMenu)
2776 hmenuprev = hmenutmp;
2777 hmenutmp = MENU_GetSubPopup( hmenuprev );
2780 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2781 pmt->hCurrentMenu = hmenuprev;
2789 /***********************************************************************
2792 * Handle a VK_LEFT key event in a menu.
2794 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2797 HMENU hmenutmp, hmenuprev;
2800 hmenuprev = hmenutmp = pmt->hTopMenu;
2801 menu = MENU_GetMenu( hmenutmp );
2803 /* Try to move 1 column left (if possible) */
2804 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2805 NO_SELECTED_ITEM ) {
2807 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2812 /* close topmost popup */
2813 while (hmenutmp != pmt->hCurrentMenu)
2815 hmenuprev = hmenutmp;
2816 hmenutmp = MENU_GetSubPopup( hmenuprev );
2819 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2820 pmt->hCurrentMenu = hmenuprev;
2822 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2824 /* move menu bar selection if no more popups are left */
2826 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2827 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2829 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2831 /* A sublevel menu was displayed - display the next one
2832 * unless there is another displacement coming up */
2834 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2835 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2836 pmt->hTopMenu, TRUE, wFlags);
2842 /***********************************************************************
2845 * Handle a VK_RIGHT key event in a menu.
2847 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2850 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2853 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2855 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->items[0].text),
2856 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2858 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2860 /* If already displaying a popup, try to display sub-popup */
2862 hmenutmp = pmt->hCurrentMenu;
2863 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2865 /* if subpopup was displayed then we are done */
2866 if (hmenutmp != pmt->hCurrentMenu) return;
2869 /* Check to see if there's another column */
2870 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2871 NO_SELECTED_ITEM ) {
2872 TRACE("Going to %d.\n", nextcol );
2873 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2878 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2880 if( pmt->hCurrentMenu != pmt->hTopMenu )
2882 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2883 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2884 } else hmenutmp = 0;
2886 /* try to move to the next item */
2887 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2888 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2890 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2891 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2892 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2893 pmt->hTopMenu, TRUE, wFlags);
2897 /***********************************************************************
2900 * Menu tracking code.
2902 static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2903 HWND hwnd, const RECT *lprect )
2908 INT executedMenuId = -1;
2910 BOOL enterIdleSent = FALSE;
2913 mt.hCurrentMenu = hmenu;
2914 mt.hTopMenu = hmenu;
2915 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2919 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p %s\n",
2920 hmenu, wFlags, x, y, hwnd, wine_dbgstr_rect( lprect));
2923 if (!(menu = MENU_GetMenu( hmenu )))
2925 WARN("Invalid menu handle %p\n", hmenu);
2926 SetLastError(ERROR_INVALID_MENU_HANDLE);
2930 if (wFlags & TPM_BUTTONDOWN)
2932 /* Get the result in order to start the tracking or not */
2933 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2934 fEndMenu = !fRemove;
2937 if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
2939 MENU_SetCapture( mt.hOwnerWnd );
2943 menu = MENU_GetMenu( mt.hCurrentMenu );
2944 if (!menu) /* sometimes happens if I do a window manager close */
2947 /* we have to keep the message in the queue until it's
2948 * clear that menu loop is not over yet. */
2952 if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
2954 if (!CallMsgFilterW( &msg, MSGF_MENU )) break;
2955 /* remove the message from the queue */
2956 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2962 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2963 enterIdleSent = TRUE;
2964 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2970 /* check if EndMenu() tried to cancel us, by posting this message */
2971 if(msg.message == WM_CANCELMODE)
2973 /* we are now out of the loop */
2976 /* remove the message from the queue */
2977 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2979 /* break out of internal loop, ala ESCAPE */
2983 TranslateMessage( &msg );
2986 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2987 enterIdleSent=FALSE;
2990 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2993 * Use the mouse coordinates in lParam instead of those in the MSG
2994 * struct to properly handle synthetic messages. They are already
2995 * in screen coordinates.
2997 mt.pt.x = (short)LOWORD(msg.lParam);
2998 mt.pt.y = (short)HIWORD(msg.lParam);
3000 /* Find a menu for this mouse event */
3001 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
3005 /* no WM_NC... messages in captured state */
3007 case WM_RBUTTONDBLCLK:
3008 case WM_RBUTTONDOWN:
3009 if (!(wFlags & TPM_RIGHTBUTTON)) break;
3011 case WM_LBUTTONDBLCLK:
3012 case WM_LBUTTONDOWN:
3013 /* If the message belongs to the menu, removes it from the queue */
3014 /* Else, end menu tracking */
3015 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
3016 fEndMenu = !fRemove;
3020 if (!(wFlags & TPM_RIGHTBUTTON)) break;
3023 /* Check if a menu was selected by the mouse */
3026 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
3028 /* End the loop if executedMenuId is an item ID */
3029 /* or if the job was done (executedMenuId = 0). */
3030 fEndMenu = fRemove = (executedMenuId != -1);
3032 /* No menu was selected by the mouse */
3033 /* if the function was called by TrackPopupMenu, continue
3034 with the menu tracking. If not, stop it */
3036 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
3041 /* the selected menu item must be changed every time */
3042 /* the mouse moves. */
3045 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
3047 } /* switch(msg.message) - mouse */
3049 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
3051 fRemove = TRUE; /* Keyboard messages are always removed */
3064 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
3065 NO_SELECTED_ITEM, FALSE, 0 );
3066 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
3067 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
3071 case VK_DOWN: /* If on menu bar, pull-down the menu */
3073 menu = MENU_GetMenu( mt.hCurrentMenu );
3074 if (!(menu->wFlags & MF_POPUP))
3075 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
3076 else /* otherwise try to move selection */
3077 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
3078 (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
3082 MENU_KeyLeft( &mt, wFlags );
3086 MENU_KeyRight( &mt, wFlags );
3090 fEndMenu = MENU_KeyEscape(&mt, wFlags);
3096 hi.cbSize = sizeof(HELPINFO);
3097 hi.iContextType = HELPINFO_MENUITEM;
3098 if (menu->FocusedItem == NO_SELECTED_ITEM)
3101 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
3102 hi.hItemHandle = hmenu;
3103 hi.dwContextId = menu->dwContextHelpID;
3104 hi.MousePos = msg.pt;
3105 SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
3112 break; /* WM_KEYDOWN */
3119 if (msg.wParam == '\r' || msg.wParam == ' ')
3121 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3122 fEndMenu = (executedMenuId != -2);
3127 /* Hack to avoid control chars. */
3128 /* We will find a better way real soon... */
3129 if (msg.wParam < 32) break;
3131 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
3132 LOWORD(msg.wParam), FALSE );
3133 if (pos == (UINT)-2) fEndMenu = TRUE;
3134 else if (pos == (UINT)-1) MessageBeep(0);
3137 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
3139 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3140 fEndMenu = (executedMenuId != -2);
3144 } /* switch(msg.message) - kbd */
3148 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
3149 DispatchMessageW( &msg );
3153 if (!fEndMenu) fRemove = TRUE;
3155 /* finally remove message from the queue */
3157 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
3158 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
3159 else mt.trackFlags &= ~TF_SKIPREMOVE;
3162 MENU_SetCapture(0); /* release the capture */
3164 /* If dropdown is still painted and the close box is clicked on
3165 then the menu will be destroyed as part of the DispatchMessage above.
3166 This will then invalidate the menu handle in mt.hTopMenu. We should
3167 check for this first. */
3168 if( IsMenu( mt.hTopMenu ) )
3170 menu = MENU_GetMenu( mt.hTopMenu );
3172 if( IsWindow( mt.hOwnerWnd ) )
3174 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
3176 if (menu && (menu->wFlags & MF_POPUP))
3178 DestroyWindow( menu->hWnd );
3181 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3182 SendMessageW( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
3185 /* Reset the variable for hiding menu */
3186 if( menu ) menu->bTimeToHide = FALSE;
3189 /* The return value is only used by TrackPopupMenu */
3190 if (!(wFlags & TPM_RETURNCMD)) return TRUE;
3191 if (executedMenuId < 0) executedMenuId = 0;
3192 return executedMenuId;
3195 /***********************************************************************
3198 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
3202 TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
3206 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3207 if (!(wFlags & TPM_NONOTIFY))
3208 SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
3210 SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
3212 if (!(wFlags & TPM_NONOTIFY))
3214 SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
3215 /* If an app changed/recreated menu bar entries in WM_INITMENU
3216 * menu sizes will be recalculated once the menu created/shown.
3220 /* This makes the menus of applications built with Delphi work.
3221 * It also enables menus to be displayed in more than one window,
3222 * but there are some bugs left that need to be fixed in this case.
3224 if ((menu = MENU_GetMenu( hMenu ))) menu->hWnd = hWnd;
3228 /***********************************************************************
3231 static BOOL MENU_ExitTracking(HWND hWnd)
3233 TRACE("hwnd=%p\n", hWnd);
3235 SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 );
3241 /***********************************************************************
3242 * MENU_TrackMouseMenuBar
3244 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3246 void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
3248 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
3249 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3251 TRACE("wnd=%p ht=0x%04x %s\n", hWnd, ht, wine_dbgstr_point( &pt));
3255 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
3256 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
3257 MENU_ExitTracking(hWnd);
3262 /***********************************************************************
3263 * MENU_TrackKbdMenuBar
3265 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3267 void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar)
3269 UINT uItem = NO_SELECTED_ITEM;
3271 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3273 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
3275 /* find window that has a menu */
3277 while (!WIN_ALLOWED_MENU(GetWindowLongW( hwnd, GWL_STYLE )))
3278 if (!(hwnd = GetAncestor( hwnd, GA_PARENT ))) return;
3280 /* check if we have to track a system menu */
3282 hTrackMenu = GetMenu( hwnd );
3283 if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' )
3285 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
3286 hTrackMenu = get_win_sys_menu( hwnd );
3288 wParam |= HTSYSMENU; /* prevent item lookup */
3291 if (!IsMenu( hTrackMenu )) return;
3293 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3295 if( wChar && wChar != ' ' )
3297 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) );
3298 if ( uItem >= (UINT)(-2) )
3300 if( uItem == (UINT)(-1) ) MessageBeep(0);
3301 /* schedule end of menu tracking */
3302 wFlags |= TF_ENDMENU;
3307 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3309 if (wParam & HTSYSMENU)
3311 /* prevent sysmenu activation for managed windows on Alt down/up */
3312 if (GetPropA( hwnd, "__wine_x11_managed" ))
3313 wFlags |= TF_ENDMENU; /* schedule end of menu tracking */
3317 if( uItem == NO_SELECTED_ITEM )
3318 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3320 PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3324 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3325 MENU_ExitTracking( hwnd );
3329 /**********************************************************************
3330 * TrackPopupMenu (USER32.@)
3332 * Like the win32 API, the function return the command ID only if the
3333 * flag TPM_RETURNCMD is on.
3336 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3337 INT nReserved, HWND hWnd, const RECT *lpRect )
3341 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3343 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3344 if (!(wFlags & TPM_NONOTIFY))
3345 SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0);
3347 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3348 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3349 MENU_ExitTracking(hWnd);
3354 /**********************************************************************
3355 * TrackPopupMenuEx (USER32.@)
3357 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3358 HWND hWnd, LPTPMPARAMS lpTpm )
3360 FIXME("not fully implemented\n" );
3361 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3362 lpTpm ? &lpTpm->rcExclude : NULL );
3365 /***********************************************************************
3368 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3370 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3372 TRACE("hwnd=%p msg=0x%04x wp=0x%04x lp=0x%08lx\n", hwnd, message, wParam, lParam);
3378 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3379 SetWindowLongPtrW( hwnd, 0, (LONG_PTR)cs->lpCreateParams );
3383 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3384 return MA_NOACTIVATE;
3389 BeginPaint( hwnd, &ps );
3390 MENU_DrawPopupMenu( hwnd, ps.hdc,
3391 (HMENU)GetWindowLongPtrW( hwnd, 0 ) );
3392 EndPaint( hwnd, &ps );
3399 /* zero out global pointer in case resident popup window was destroyed. */
3400 if (hwnd == top_popup) top_popup = 0;
3407 if (!GetWindowLongPtrW( hwnd, 0 )) ERR("no menu to display\n");
3410 SetWindowLongPtrW( hwnd, 0, 0 );
3413 case MM_SETMENUHANDLE:
3414 SetWindowLongPtrW( hwnd, 0, wParam );
3417 case MM_GETMENUHANDLE:
3418 return GetWindowLongPtrW( hwnd, 0 );
3421 return DefWindowProcW( hwnd, message, wParam, lParam );
3427 /***********************************************************************
3428 * MENU_GetMenuBarHeight
3430 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3432 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3433 INT orgX, INT orgY )
3439 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
3441 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3443 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3444 SelectObject( hdc, get_menu_font(FALSE));
3445 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3446 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3447 ReleaseDC( hwnd, hdc );
3448 return lppop->Height;
3452 /*******************************************************************
3453 * ChangeMenuA (USER32.@)
3455 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3456 UINT id, UINT flags )
3458 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3459 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3461 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3462 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3464 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3465 flags & MF_BYPOSITION ? pos : id,
3466 flags & ~MF_REMOVE );
3467 /* Default: MF_INSERT */
3468 return InsertMenuA( hMenu, pos, flags, id, data );
3472 /*******************************************************************
3473 * ChangeMenuW (USER32.@)
3475 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3476 UINT id, UINT flags )
3478 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3479 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3481 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3482 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3484 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3485 flags & MF_BYPOSITION ? pos : id,
3486 flags & ~MF_REMOVE );
3487 /* Default: MF_INSERT */
3488 return InsertMenuW( hMenu, pos, flags, id, data );
3492 /*******************************************************************
3493 * CheckMenuItem (USER32.@)
3495 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3500 TRACE("menu=%p id=%04x flags=%04x\n", hMenu, id, flags );
3501 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3502 ret = item->fState & MF_CHECKED;
3503 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3504 else item->fState &= ~MF_CHECKED;
3509 /**********************************************************************
3510 * EnableMenuItem (USER32.@)
3512 BOOL WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3518 TRACE("(%p, %04x, %04x) !\n", hMenu, wItemID, wFlags);
3520 /* Get the Popupmenu to access the owner menu */
3521 if (!(menu = MENU_GetMenu(hMenu)))
3524 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3527 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3528 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3530 /* If the close item in the system menu change update the close button */
3531 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3533 if (menu->hSysMenuOwner != 0)
3536 POPUPMENU* parentMenu;
3538 /* Get the parent menu to access*/
3539 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3542 /* Refresh the frame to reflect the change */
3543 GetWindowRect(parentMenu->hWnd, &rc);
3544 MapWindowPoints(0, parentMenu->hWnd, (POINT *)&rc, 2);
3546 RedrawWindow(parentMenu->hWnd, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
3554 /*******************************************************************
3555 * GetMenuStringA (USER32.@)
3557 INT WINAPI GetMenuStringA(
3558 HMENU hMenu, /* [in] menuhandle */
3559 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3560 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3561 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3562 UINT wFlags /* [in] MF_ flags */
3566 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3567 if (str && nMaxSiz) str[0] = '\0';
3568 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
3569 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
3572 if (!item->text) return 0;
3573 if (!str || !nMaxSiz) return strlenW(item->text);
3574 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3576 TRACE("returning '%s'\n", str );
3581 /*******************************************************************
3582 * GetMenuStringW (USER32.@)
3584 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3585 LPWSTR str, INT nMaxSiz, UINT wFlags )
3589 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3590 if (str && nMaxSiz) str[0] = '\0';
3591 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
3592 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
3595 if (!str || !nMaxSiz) return item->text ? strlenW(item->text) : 0;
3596 if( !(item->text)) {
3600 lstrcpynW( str, item->text, nMaxSiz );
3601 return strlenW(str);
3605 /**********************************************************************
3606 * HiliteMenuItem (USER32.@)
3608 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3612 TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
3613 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3614 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3615 if (menu->FocusedItem == wItemID) return TRUE;
3616 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3617 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3622 /**********************************************************************
3623 * GetMenuState (USER32.@)
3625 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3628 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, wItemID, wFlags);
3629 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3630 debug_print_menuitem (" item: ", item, "");
3631 if (item->fType & MF_POPUP)
3633 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3634 if (!menu) return -1;
3635 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3639 /* We used to (from way back then) mask the result to 0xff. */
3640 /* I don't know why and it seems wrong as the documented */
3641 /* return flag MF_SEPARATOR is outside that mask. */
3642 return (item->fType | item->fState);
3647 /**********************************************************************
3648 * GetMenuItemCount (USER32.@)
3650 INT WINAPI GetMenuItemCount( HMENU hMenu )
3652 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3653 if (!menu) return -1;
3654 TRACE("(%p) returning %d\n", hMenu, menu->nItems );
3655 return menu->nItems;
3659 /**********************************************************************
3660 * GetMenuItemID (USER32.@)
3662 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3666 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
3667 if (lpmi->fType & MF_POPUP) return -1;
3673 /*******************************************************************
3674 * InsertMenuW (USER32.@)
3676 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3677 UINT_PTR id, LPCWSTR str )
3681 if (IS_STRING_ITEM(flags) && str)
3682 TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3683 hMenu, pos, flags, id, debugstr_w(str) );
3684 else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %p (not a string)\n",
3685 hMenu, pos, flags, id, str );
3687 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3689 if (!(MENU_SetItemData( item, flags, id, str )))
3691 RemoveMenu( hMenu, pos, flags );
3695 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3696 (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
3698 item->hCheckBit = item->hUnCheckBit = 0;
3703 /*******************************************************************
3704 * InsertMenuA (USER32.@)
3706 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3707 UINT_PTR id, LPCSTR str )
3711 if (IS_STRING_ITEM(flags) && str)
3713 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3714 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3717 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3718 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3719 HeapFree( GetProcessHeap(), 0, newstr );
3723 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3727 /*******************************************************************
3728 * AppendMenuA (USER32.@)
3730 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3731 UINT_PTR id, LPCSTR data )
3733 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3737 /*******************************************************************
3738 * AppendMenuW (USER32.@)
3740 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3741 UINT_PTR id, LPCWSTR data )
3743 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3747 /**********************************************************************
3748 * RemoveMenu (USER32.@)
3750 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3755 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3756 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3757 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3761 MENU_FreeItemData( item );
3763 if (--menu->nItems == 0)
3765 HeapFree( GetProcessHeap(), 0, menu->items );
3770 while(nPos < menu->nItems)
3776 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3777 menu->nItems * sizeof(MENUITEM) );
3783 /**********************************************************************
3784 * DeleteMenu (USER32.@)
3786 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3788 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3789 if (!item) return FALSE;
3790 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3791 /* nPos is now the position of the item */
3792 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3797 /*******************************************************************
3798 * ModifyMenuW (USER32.@)
3800 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3801 UINT_PTR id, LPCWSTR str )
3805 if (IS_STRING_ITEM(flags))
3806 TRACE("%p %d %04x %04x %s\n", hMenu, pos, flags, id, debugstr_w(str) );
3808 TRACE("%p %d %04x %04x %p\n", hMenu, pos, flags, id, str );
3810 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3811 MENU_GetMenu(hMenu)->Height = 0; /* force size recalculate */
3812 return MENU_SetItemData( item, flags, id, str );
3816 /*******************************************************************
3817 * ModifyMenuA (USER32.@)
3819 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3820 UINT_PTR id, LPCSTR str )
3824 if (IS_STRING_ITEM(flags) && str)
3826 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3827 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3830 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3831 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3832 HeapFree( GetProcessHeap(), 0, newstr );
3836 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3840 /**********************************************************************
3841 * CreatePopupMenu (USER32.@)
3843 HMENU WINAPI CreatePopupMenu(void)
3848 if (!(hmenu = CreateMenu())) return 0;
3849 menu = MENU_GetMenu( hmenu );
3850 menu->wFlags |= MF_POPUP;
3851 menu->bTimeToHide = FALSE;
3856 /**********************************************************************
3857 * GetMenuCheckMarkDimensions (USER.417)
3858 * GetMenuCheckMarkDimensions (USER32.@)
3860 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3862 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3866 /**********************************************************************
3867 * SetMenuItemBitmaps (USER32.@)
3869 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3870 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3873 TRACE("(%p, %04x, %04x, %p, %p)\n",
3874 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3875 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3877 if (!hNewCheck && !hNewUnCheck)
3879 item->fState &= ~MF_USECHECKBITMAPS;
3881 else /* Install new bitmaps */
3883 item->hCheckBit = hNewCheck;
3884 item->hUnCheckBit = hNewUnCheck;
3885 item->fState |= MF_USECHECKBITMAPS;
3891 /**********************************************************************
3892 * CreateMenu (USER32.@)
3894 HMENU WINAPI CreateMenu(void)
3898 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3899 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3901 ZeroMemory(menu, sizeof(POPUPMENU));
3902 menu->wMagic = MENU_MAGIC;
3903 menu->FocusedItem = NO_SELECTED_ITEM;
3904 menu->bTimeToHide = FALSE;
3906 TRACE("return %p\n", hMenu );
3912 /**********************************************************************
3913 * DestroyMenu (USER32.@)
3915 BOOL WINAPI DestroyMenu( HMENU hMenu )
3917 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3919 TRACE("(%p)\n", hMenu);
3922 if (!lppop) return FALSE;
3924 lppop->wMagic = 0; /* Mark it as destroyed */
3926 /* DestroyMenu should not destroy system menu popup owner */
3927 if ((lppop->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && lppop->hWnd)
3929 DestroyWindow( lppop->hWnd );
3933 if (lppop->items) /* recursively destroy submenus */
3936 MENUITEM *item = lppop->items;
3937 for (i = lppop->nItems; i > 0; i--, item++)
3939 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3940 MENU_FreeItemData( item );
3942 HeapFree( GetProcessHeap(), 0, lppop->items );
3944 USER_HEAP_FREE( hMenu );
3949 /**********************************************************************
3950 * GetSystemMenu (USER32.@)
3952 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3954 WND *wndPtr = WIN_GetPtr( hWnd );
3957 if (wndPtr == WND_DESKTOP) return 0;
3958 if (wndPtr == WND_OTHER_PROCESS)
3960 if (IsWindow( hWnd )) FIXME( "not supported on other process window %p\n", hWnd );
3964 if (wndPtr->hSysMenu && bRevert)
3966 DestroyMenu(wndPtr->hSysMenu);
3967 wndPtr->hSysMenu = 0;
3970 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3971 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, 0 );
3973 if( wndPtr->hSysMenu )
3976 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3978 /* Store the dummy sysmenu handle to facilitate the refresh */
3979 /* of the close button if the SC_CLOSE item change */
3980 menu = MENU_GetMenu(retvalue);
3982 menu->hSysMenuOwner = wndPtr->hSysMenu;
3984 WIN_ReleasePtr( wndPtr );
3986 return bRevert ? 0 : retvalue;
3990 /*******************************************************************
3991 * SetSystemMenu (USER32.@)
3993 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3995 WND *wndPtr = WIN_GetPtr( hwnd );
3997 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
3999 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
4000 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
4001 WIN_ReleasePtr( wndPtr );
4008 /**********************************************************************
4009 * GetMenu (USER32.@)
4011 HMENU WINAPI GetMenu( HWND hWnd )
4013 HMENU retvalue = (HMENU)GetWindowLongPtrW( hWnd, GWLP_ID );
4014 TRACE("for %p returning %p\n", hWnd, retvalue);
4018 /**********************************************************************
4019 * GetMenuBarInfo (USER32.@)
4021 BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi )
4023 FIXME( "(%p,0x%08lx,0x%08lx,%p)\n", hwnd, idObject, idItem, pmbi );
4027 /**********************************************************************
4030 * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
4031 * SetWindowPos call that would result if SetMenu were called directly.
4033 BOOL MENU_SetMenu( HWND hWnd, HMENU hMenu )
4035 TRACE("(%p, %p);\n", hWnd, hMenu);
4037 if (hMenu && !IsMenu(hMenu))
4039 WARN("hMenu %p is not a menu handle\n", hMenu);
4040 SetLastError(ERROR_INVALID_MENU_HANDLE);
4043 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
4046 hWnd = WIN_GetFullHandle( hWnd );
4047 if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */
4053 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
4055 lpmenu->hWnd = hWnd;
4056 lpmenu->Height = 0; /* Make sure we recalculate the size */
4058 SetWindowLongPtrW( hWnd, GWLP_ID, (LONG_PTR)hMenu );
4063 /**********************************************************************
4064 * SetMenu (USER32.@)
4066 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4068 if(!MENU_SetMenu(hWnd, hMenu))
4071 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4072 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4077 /**********************************************************************
4078 * GetSubMenu (USER32.@)
4080 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4084 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return 0;
4085 if (!(lpmi->fType & MF_POPUP)) return 0;
4086 return lpmi->hSubMenu;
4090 /**********************************************************************
4091 * DrawMenuBar (USER32.@)
4093 BOOL WINAPI DrawMenuBar( HWND hWnd )
4096 HMENU hMenu = GetMenu(hWnd);
4098 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
4100 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4102 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4103 lppop->hwndOwner = hWnd;
4104 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4105 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4109 /***********************************************************************
4110 * DrawMenuBarTemp (USER32.@)
4114 * called by W98SE desk.cpl Control Panel Applet
4116 * Not 100% sure about the param names, but close.
4118 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont)
4123 BOOL flat_menu = FALSE;
4125 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
4128 hMenu = GetMenu(hwnd);
4131 hFont = get_menu_font(FALSE);
4133 lppop = MENU_GetMenu( hMenu );
4134 if (lppop == NULL || lprect == NULL)
4136 retvalue = GetSystemMetrics(SM_CYMENU);
4140 TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont);
4142 hfontOld = SelectObject( hDC, hFont);
4144 if (lppop->Height == 0)
4145 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
4147 lprect->bottom = lprect->top + lppop->Height;
4149 FillRect(hDC, lprect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU) );
4151 SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE));
4152 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
4153 LineTo( hDC, lprect->right, lprect->bottom );
4155 if (lppop->nItems == 0)
4157 retvalue = GetSystemMetrics(SM_CYMENU);
4161 for (i = 0; i < lppop->nItems; i++)
4163 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
4164 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
4166 retvalue = lppop->Height;
4169 if (hfontOld) SelectObject (hDC, hfontOld);
4173 /***********************************************************************
4174 * EndMenu (USER.187)
4175 * EndMenu (USER32.@)
4177 void WINAPI EndMenu(void)
4179 /* if we are in the menu code, and it is active */
4180 if (!fEndMenu && top_popup)
4182 /* terminate the menu handling code */
4185 /* needs to be posted to wakeup the internal menu handler */
4186 /* which will now terminate the menu, in the event that */
4187 /* the main window was minimized, or lost focus, so we */
4188 /* don't end up with an orphaned menu */
4189 PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
4194 /***********************************************************************
4195 * LookupMenuHandle (USER.217)
4197 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4199 HMENU hmenu32 = HMENU_32(hmenu);
4201 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4202 else return HMENU_16(hmenu32);
4206 /**********************************************************************
4207 * LoadMenu (USER.150)
4209 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4215 if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4216 if (!name) return 0;
4218 instance = GetExePtr( instance );
4219 if (!(hRsrc = FindResource16( instance, name, (LPSTR)RT_MENU ))) return 0;
4220 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4221 hMenu = LoadMenuIndirect16(LockResource16(handle));
4222 FreeResource16( handle );
4227 /*****************************************************************
4228 * LoadMenuA (USER32.@)
4230 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4232 HRSRC hrsrc = FindResourceA( instance, name, (LPSTR)RT_MENU );
4233 if (!hrsrc) return 0;
4234 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4238 /*****************************************************************
4239 * LoadMenuW (USER32.@)
4241 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4243 HRSRC hrsrc = FindResourceW( instance, name, (LPWSTR)RT_MENU );
4244 if (!hrsrc) return 0;
4245 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4249 /**********************************************************************
4250 * LoadMenuIndirect (USER.220)
4252 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4255 WORD version, offset;
4256 LPCSTR p = (LPCSTR)template;
4258 TRACE("(%p)\n", template );
4259 version = GET_WORD(p);
4263 WARN("version must be 0 for Win16\n" );
4266 offset = GET_WORD(p);
4267 p += sizeof(WORD) + offset;
4268 if (!(hMenu = CreateMenu())) return 0;
4269 if (!MENU_ParseResource( p, hMenu, FALSE ))
4271 DestroyMenu( hMenu );
4274 return HMENU_16(hMenu);
4278 /**********************************************************************
4279 * LoadMenuIndirectW (USER32.@)
4281 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4284 WORD version, offset;
4285 LPCSTR p = (LPCSTR)template;
4287 version = GET_WORD(p);
4289 TRACE("%p, ver %d\n", template, version );
4292 case 0: /* standard format is version of 0 */
4293 offset = GET_WORD(p);
4294 p += sizeof(WORD) + offset;
4295 if (!(hMenu = CreateMenu())) return 0;
4296 if (!MENU_ParseResource( p, hMenu, TRUE ))
4298 DestroyMenu( hMenu );
4302 case 1: /* extended format is version of 1 */
4303 offset = GET_WORD(p);
4304 p += sizeof(WORD) + offset;
4305 if (!(hMenu = CreateMenu())) return 0;
4306 if (!MENUEX_ParseResource( p, hMenu))
4308 DestroyMenu( hMenu );
4313 ERR("version %d not supported.\n", version);
4319 /**********************************************************************
4320 * LoadMenuIndirectA (USER32.@)
4322 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4324 return LoadMenuIndirectW( template );
4328 /**********************************************************************
4331 BOOL WINAPI IsMenu(HMENU hmenu)
4333 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4334 return menu != NULL;
4337 /**********************************************************************
4338 * GetMenuItemInfo_common
4341 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4342 LPMENUITEMINFOW lpmii, BOOL unicode)
4344 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4346 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4351 if( lpmii->fMask & MIIM_TYPE) {
4352 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4353 WARN("invalid combination of fMask bits used\n");
4354 /* this does not happen on Win9x/ME */
4355 SetLastError( ERROR_INVALID_PARAMETER);
4358 lpmii->fType = menu->fType & ~MF_POPUP;
4359 if( menu->hbmpItem) lpmii->fType |= MFT_BITMAP;
4360 lpmii->hbmpItem = menu->hbmpItem; /* not on Win9x/ME */
4361 if( lpmii->fType & MFT_BITMAP) {
4362 lpmii->dwTypeData = (LPWSTR) menu->hbmpItem;
4364 } else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR)) {
4365 /* this does not happen on Win9x/ME */
4366 lpmii->dwTypeData = 0;
4371 /* copy the text string */
4372 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING))) {
4374 if(lpmii->dwTypeData && lpmii->cch) {
4377 *((WCHAR *)lpmii->dwTypeData) = 0;
4379 *((CHAR *)lpmii->dwTypeData) = 0;
4385 len = strlenW(menu->text);
4386 if(lpmii->dwTypeData && lpmii->cch)
4387 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4391 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL,
4392 0, NULL, NULL ) - 1;
4393 if(lpmii->dwTypeData && lpmii->cch)
4394 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4395 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4396 ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
4398 /* if we've copied a substring we return its length */
4399 if(lpmii->dwTypeData && lpmii->cch)
4400 if (lpmii->cch <= len + 1)
4405 /* return length of string */
4406 /* not on Win9x/ME if fType & MFT_BITMAP */
4412 if (lpmii->fMask & MIIM_FTYPE)
4413 lpmii->fType = menu->fType & ~MF_POPUP;
4415 if (lpmii->fMask & MIIM_BITMAP)
4416 lpmii->hbmpItem = menu->hbmpItem;
4418 if (lpmii->fMask & MIIM_STATE)
4419 lpmii->fState = menu->fState;
4421 if (lpmii->fMask & MIIM_ID)
4422 lpmii->wID = menu->wID;
4424 if (lpmii->fMask & MIIM_SUBMENU)
4425 lpmii->hSubMenu = menu->hSubMenu;
4427 /* hSubMenu is always cleared
4428 * (not on Win9x/ME ) */
4429 lpmii->hSubMenu = 0;
4432 if (lpmii->fMask & MIIM_CHECKMARKS) {
4433 lpmii->hbmpChecked = menu->hCheckBit;
4434 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4436 if (lpmii->fMask & MIIM_DATA)
4437 lpmii->dwItemData = menu->dwItemData;
4442 /**********************************************************************
4443 * GetMenuItemInfoA (USER32.@)
4445 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4446 LPMENUITEMINFOA lpmii)
4450 if( lpmii->cbSize != sizeof( mii) &&
4451 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4452 SetLastError( ERROR_INVALID_PARAMETER);
4455 memcpy( &mii, lpmii, lpmii->cbSize);
4456 mii.cbSize = sizeof( mii);
4457 ret = GetMenuItemInfo_common (hmenu, item, bypos,
4458 (LPMENUITEMINFOW)&mii, FALSE);
4459 mii.cbSize = lpmii->cbSize;
4460 memcpy( lpmii, &mii, mii.cbSize);
4464 /**********************************************************************
4465 * GetMenuItemInfoW (USER32.@)
4467 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4468 LPMENUITEMINFOW lpmii)
4472 if( lpmii->cbSize != sizeof( mii) &&
4473 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4474 SetLastError( ERROR_INVALID_PARAMETER);
4477 memcpy( &mii, lpmii, lpmii->cbSize);
4478 mii.cbSize = sizeof( mii);
4479 ret = GetMenuItemInfo_common (hmenu, item, bypos, &mii, TRUE);
4480 mii.cbSize = lpmii->cbSize;
4481 memcpy( lpmii, &mii, mii.cbSize);
4486 /* set a menu item text from a ASCII or Unicode string */
4487 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4493 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4494 strcpyW( menu->text, text );
4498 LPCSTR str = (LPCSTR)text;
4499 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4500 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4501 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4506 /**********************************************************************
4507 * SetMenuItemInfo_common
4510 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4511 const MENUITEMINFOW *lpmii,
4514 if (!menu) return FALSE;
4516 debug_print_menuitem("SetmenuItemInfo_common from: ", menu, "");
4518 if (lpmii->fMask & MIIM_TYPE ) {
4519 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4520 WARN("invalid combination of fMask bits used\n");
4521 /* this does not happen on Win9x/ME */
4522 SetLastError( ERROR_INVALID_PARAMETER);
4525 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4526 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4527 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4529 if (IS_STRING_ITEM(menu->fType)) {
4530 HeapFree(GetProcessHeap(), 0, menu->text);
4531 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4532 } else if( (menu->fType) & MFT_BITMAP)
4533 menu->hbmpItem = (HBITMAP)lpmii->dwTypeData;
4536 if (lpmii->fMask & MIIM_FTYPE ) {
4537 if(( lpmii->fType & MFT_BITMAP)) {
4538 SetLastError( ERROR_INVALID_PARAMETER);
4541 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4542 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4544 if (lpmii->fMask & MIIM_STRING ) {
4545 /* free the string when used */
4546 HeapFree(GetProcessHeap(), 0, menu->text);
4547 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4550 if (lpmii->fMask & MIIM_STATE)
4552 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4553 menu->fState = lpmii->fState;
4556 if (lpmii->fMask & MIIM_ID)
4557 menu->wID = lpmii->wID;
4559 if (lpmii->fMask & MIIM_SUBMENU) {
4560 menu->hSubMenu = lpmii->hSubMenu;
4561 if (menu->hSubMenu) {
4562 POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
4564 subMenu->wFlags |= MF_POPUP;
4565 menu->fType |= MF_POPUP;
4568 SetLastError( ERROR_INVALID_PARAMETER);
4573 menu->fType &= ~MF_POPUP;
4576 if (lpmii->fMask & MIIM_CHECKMARKS)
4578 if (lpmii->fType & MFT_RADIOCHECK)
4579 menu->fType |= MFT_RADIOCHECK;
4581 menu->hCheckBit = lpmii->hbmpChecked;
4582 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4584 if (lpmii->fMask & MIIM_DATA)
4585 menu->dwItemData = lpmii->dwItemData;
4587 if (lpmii->fMask & MIIM_BITMAP)
4588 menu->hbmpItem = lpmii->hbmpItem;
4590 if( !menu->text && !(menu->fType & MFT_OWNERDRAW) && !menu->hbmpItem)
4591 menu->fType |= MFT_SEPARATOR;
4593 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4597 /**********************************************************************
4598 * SetMenuItemInfoA (USER32.@)
4600 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4601 const MENUITEMINFOA *lpmii)
4604 if( lpmii->cbSize != sizeof( mii) &&
4605 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4606 SetLastError( ERROR_INVALID_PARAMETER);
4609 memcpy( &mii, lpmii, lpmii->cbSize);
4610 if( lpmii->cbSize != sizeof( mii)) {
4611 mii.cbSize = sizeof( mii);
4612 mii.hbmpItem = NULL;
4614 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4615 (const MENUITEMINFOW *)&mii, FALSE);
4618 /**********************************************************************
4619 * SetMenuItemInfoW (USER32.@)
4621 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4622 const MENUITEMINFOW *lpmii)
4625 if( lpmii->cbSize != sizeof( mii) &&
4626 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4627 SetLastError( ERROR_INVALID_PARAMETER);
4630 memcpy( &mii, lpmii, lpmii->cbSize);
4631 if( lpmii->cbSize != sizeof( mii)) {
4632 mii.cbSize = sizeof( mii);
4633 mii.hbmpItem = NULL;
4635 return SetMenuItemInfo_common(MENU_FindItem(&hmenu,
4636 &item, bypos? MF_BYPOSITION : 0), &mii, TRUE);
4639 /**********************************************************************
4640 * SetMenuDefaultItem (USER32.@)
4643 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4649 TRACE("(%p,%d,%d)\n", hmenu, uItem, bypos);
4651 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4653 /* reset all default-item flags */
4655 for (i = 0; i < menu->nItems; i++, item++)
4657 item->fState &= ~MFS_DEFAULT;
4660 /* no default item */
4669 if ( uItem >= menu->nItems ) return FALSE;
4670 item[uItem].fState |= MFS_DEFAULT;
4675 for (i = 0; i < menu->nItems; i++, item++)
4677 if (item->wID == uItem)
4679 item->fState |= MFS_DEFAULT;
4688 /**********************************************************************
4689 * GetMenuDefaultItem (USER32.@)
4691 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4697 TRACE("(%p,%d,%d)\n", hmenu, bypos, flags);
4699 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4701 /* find default item */
4705 if (! item) return -1;
4707 while ( !( item->fState & MFS_DEFAULT ) )
4710 if (i >= menu->nItems ) return -1;
4713 /* default: don't return disabled items */
4714 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4716 /* search rekursiv when needed */
4717 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4720 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4721 if ( -1 != ret ) return ret;
4723 /* when item not found in submenu, return the popup item */
4725 return ( bypos ) ? i : item->wID;
4730 /**********************************************************************
4731 * InsertMenuItemA (USER32.@)
4733 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4734 const MENUITEMINFOA *lpmii)
4736 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4738 if( lpmii->cbSize != sizeof( mii) &&
4739 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4740 SetLastError( ERROR_INVALID_PARAMETER);
4743 memcpy( &mii, lpmii, lpmii->cbSize);
4744 if( lpmii->cbSize != sizeof( mii)) {
4745 mii.cbSize = sizeof( mii);
4746 mii.hbmpItem = NULL;
4748 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)&mii, FALSE);
4752 /**********************************************************************
4753 * InsertMenuItemW (USER32.@)
4755 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4756 const MENUITEMINFOW *lpmii)
4758 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4760 if( lpmii->cbSize != sizeof( mii) &&
4761 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4762 SetLastError( ERROR_INVALID_PARAMETER);
4765 memcpy( &mii, lpmii, lpmii->cbSize);
4766 if( lpmii->cbSize != sizeof( mii)) {
4767 mii.cbSize = sizeof( mii);
4768 mii.hbmpItem = NULL;
4770 return SetMenuItemInfo_common(item, &mii, TRUE);
4773 /**********************************************************************
4774 * CheckMenuRadioItem (USER32.@)
4777 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4778 UINT first, UINT last, UINT check,
4781 MENUITEM *mifirst, *milast, *micheck;
4782 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4784 TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos);
4786 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4787 milast = MENU_FindItem (&mlast, &last, bypos);
4788 micheck = MENU_FindItem (&mcheck, &check, bypos);
4790 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4791 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4792 micheck > milast || micheck < mifirst)
4795 while (mifirst <= milast)
4797 if (mifirst == micheck)
4799 mifirst->fType |= MFT_RADIOCHECK;
4800 mifirst->fState |= MFS_CHECKED;
4802 mifirst->fType &= ~MFT_RADIOCHECK;
4803 mifirst->fState &= ~MFS_CHECKED;
4812 /**********************************************************************
4813 * GetMenuItemRect (USER32.@)
4815 * ATTENTION: Here, the returned values in rect are the screen
4816 * coordinates of the item just like if the menu was
4817 * always on the upper left side of the application.
4820 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4823 POPUPMENU *itemMenu;
4827 TRACE("(%p,%p,%d,%p)\n", hwnd, hMenu, uItem, rect);
4829 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4830 referenceHwnd = hwnd;
4834 itemMenu = MENU_GetMenu(hMenu);
4835 if (itemMenu == NULL)
4838 if(itemMenu->hWnd == 0)
4840 referenceHwnd = itemMenu->hWnd;
4843 if ((rect == NULL) || (item == NULL))
4848 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4854 /**********************************************************************
4855 * SetMenuInfo (USER32.@)
4858 * MIM_APPLYTOSUBMENUS
4859 * actually use the items to draw the menu
4861 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4865 TRACE("(%p %p)\n", hMenu, lpmi);
4867 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4870 if (lpmi->fMask & MIM_BACKGROUND)
4871 menu->hbrBack = lpmi->hbrBack;
4873 if (lpmi->fMask & MIM_HELPID)
4874 menu->dwContextHelpID = lpmi->dwContextHelpID;
4876 if (lpmi->fMask & MIM_MAXHEIGHT)
4877 menu->cyMax = lpmi->cyMax;
4879 if (lpmi->fMask & MIM_MENUDATA)
4880 menu->dwMenuData = lpmi->dwMenuData;
4882 if (lpmi->fMask & MIM_STYLE)
4884 menu->dwStyle = lpmi->dwStyle;
4885 if (menu->dwStyle & MNS_AUTODISMISS) FIXME("MNS_AUTODISMISS unimplemented\n");
4886 if (menu->dwStyle & MNS_DRAGDROP) FIXME("MNS_DRAGDROP unimplemented\n");
4887 if (menu->dwStyle & MNS_MODELESS) FIXME("MNS_MODELESS unimplemented\n");
4888 if (menu->dwStyle & MNS_NOTIFYBYPOS) FIXME("MNS_NOTIFYBYPOS unimplemented\n");
4896 /**********************************************************************
4897 * GetMenuInfo (USER32.@)
4903 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4906 TRACE("(%p %p)\n", hMenu, lpmi);
4908 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4911 if (lpmi->fMask & MIM_BACKGROUND)
4912 lpmi->hbrBack = menu->hbrBack;
4914 if (lpmi->fMask & MIM_HELPID)
4915 lpmi->dwContextHelpID = menu->dwContextHelpID;
4917 if (lpmi->fMask & MIM_MAXHEIGHT)
4918 lpmi->cyMax = menu->cyMax;
4920 if (lpmi->fMask & MIM_MENUDATA)
4921 lpmi->dwMenuData = menu->dwMenuData;
4923 if (lpmi->fMask & MIM_STYLE)
4924 lpmi->dwStyle = menu->dwStyle;
4932 /**********************************************************************
4933 * SetMenuContextHelpId (USER32.@)
4935 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4939 TRACE("(%p 0x%08lx)\n", hMenu, dwContextHelpID);
4941 if ((menu = MENU_GetMenu(hMenu)))
4943 menu->dwContextHelpID = dwContextHelpID;
4950 /**********************************************************************
4951 * GetMenuContextHelpId (USER32.@)
4953 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4957 TRACE("(%p)\n", hMenu);
4959 if ((menu = MENU_GetMenu(hMenu)))
4961 return menu->dwContextHelpID;
4966 /**********************************************************************
4967 * MenuItemFromPoint (USER32.@)
4969 INT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4971 POPUPMENU *menu = MENU_GetMenu(hMenu);
4974 /*FIXME: Do we have to handle hWnd here? */
4975 if (!menu) return -1;
4976 if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
4981 /**********************************************************************
4982 * translate_accelerator
4984 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4985 BYTE fVirt, WORD key, WORD cmd )
4990 if (wParam != key) return FALSE;
4992 if (GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4993 if (GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4994 if (GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4996 if (message == WM_CHAR || message == WM_SYSCHAR)
4998 if ( !(fVirt & FVIRTKEY) && (mask & FALT) == (fVirt & FALT) )
5000 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
5006 if(fVirt & FVIRTKEY)
5008 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
5009 wParam, 0xff & HIWORD(lParam));
5011 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
5012 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
5016 if (!(lParam & 0x01000000)) /* no special_key */
5018 if ((fVirt & FALT) && (lParam & 0x20000000))
5019 { /* ^^ ALT pressed */
5020 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
5029 if (message == WM_KEYUP || message == WM_SYSKEYUP)
5033 HMENU hMenu, hSubMenu, hSysMenu;
5034 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
5036 hMenu = (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
5037 hSysMenu = get_win_sys_menu( hWnd );
5039 /* find menu item and ask application to initialize it */
5040 /* 1. in the system menu */
5041 hSubMenu = hSysMenu;
5043 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5047 if (!IsWindowEnabled(hWnd))
5051 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
5052 if(hSubMenu != hSysMenu)
5054 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
5055 TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
5056 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
5058 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
5061 else /* 2. in the window's menu */
5065 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5069 if (!IsWindowEnabled(hWnd))
5073 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
5074 if(hSubMenu != hMenu)
5076 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
5077 TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
5078 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
5080 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
5087 if (uSysStat != (UINT)-1)
5089 if (uSysStat & (MF_DISABLED|MF_GRAYED))
5096 if (uStat != (UINT)-1)
5102 if (uStat & (MF_DISABLED|MF_GRAYED))
5114 if( mesg==WM_COMMAND )
5116 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
5117 SendMessageW(hWnd, mesg, 0x10000 | cmd, 0L);
5119 else if( mesg==WM_SYSCOMMAND )
5121 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
5122 SendMessageW(hWnd, mesg, cmd, 0x00010000L);
5126 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5127 * #0: unknown (please report!)
5128 * #1: for WM_KEYUP,WM_SYSKEYUP
5129 * #2: mouse is captured
5130 * #3: window is disabled
5131 * #4: it's a disabled system menu option
5132 * #5: it's a menu option, but window is iconic
5133 * #6: it's a menu option, but disabled
5135 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
5137 ERR_(accel)(" unknown reason - please report!\n");
5142 /**********************************************************************
5143 * TranslateAcceleratorA (USER32.@)
5144 * TranslateAccelerator (USER32.@)
5146 INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg )
5149 LPACCEL16 lpAccelTbl;
5153 if (!hWnd || !msg) return 0;
5155 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5157 WARN_(accel)("invalid accel handle=%p\n", hAccel);
5161 wParam = msg->wParam;
5163 switch (msg->message)
5172 char ch = LOWORD(wParam);
5174 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
5175 wParam = MAKEWPARAM(wch, HIWORD(wParam));
5183 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
5184 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5188 if (translate_accelerator( hWnd, msg->message, wParam, msg->lParam,
5189 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5191 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5196 /**********************************************************************
5197 * TranslateAcceleratorW (USER32.@)
5199 INT WINAPI TranslateAcceleratorW( HWND hWnd, HACCEL hAccel, LPMSG msg )
5202 LPACCEL16 lpAccelTbl;
5205 if (!hWnd || !msg) return 0;
5207 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5209 WARN_(accel)("invalid accel handle=%p\n", hAccel);
5213 switch (msg->message)
5225 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
5226 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5230 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5231 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5233 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);