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.
45 #include "wine/port.h"
54 #include "wine/winbase16.h"
55 #include "wine/winuser16.h"
57 #include "wine/server.h"
58 #include "wine/unicode.h"
61 #include "user_private.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(menu);
65 WINE_DECLARE_DEBUG_CHANNEL(accel);
67 /* internal popup menu window messages */
69 #define MM_SETMENUHANDLE (WM_USER + 0)
70 #define MM_GETMENUHANDLE (WM_USER + 1)
72 /* Menu item structure */
74 /* ----------- MENUITEMINFO Stuff ----------- */
75 UINT fType; /* Item type. */
76 UINT fState; /* Item state. */
77 UINT_PTR wID; /* Item id. */
78 HMENU hSubMenu; /* Pop-up menu. */
79 HBITMAP hCheckBit; /* Bitmap when checked. */
80 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
81 LPWSTR text; /* Item text. */
82 ULONG_PTR dwItemData; /* Application defined. */
83 LPWSTR dwTypeData; /* depends on fMask */
84 HBITMAP hbmpItem; /* bitmap */
85 /* ----------- Wine stuff ----------- */
86 RECT rect; /* Item area (relative to menu window) */
87 UINT xTab; /* X position of text after Tab */
88 SIZE bmpsize; /* size needed for the HBMMENU_CALLBACK
92 /* Popup menu structure */
94 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
95 WORD wMagic; /* Magic number */
96 WORD Width; /* Width of the whole menu */
97 WORD Height; /* Height of the whole menu */
98 UINT nItems; /* Number of items in the menu */
99 HWND hWnd; /* Window containing the menu */
100 MENUITEM *items; /* Array of menu items */
101 UINT FocusedItem; /* Currently focused item */
102 HWND hwndOwner; /* window receiving the messages for ownerdraw */
103 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
104 BOOL bScrolling; /* Scroll arrows are active */
105 UINT nScrollPos; /* Current scroll position */
106 UINT nTotalHeight; /* Total height of menu items inside menu */
107 /* ------------ MENUINFO members ------ */
108 DWORD dwStyle; /* Extended menu style */
109 UINT cyMax; /* max height of the whole menu, 0 is screen height */
110 HBRUSH hbrBack; /* brush for menu background */
111 DWORD dwContextHelpID;
112 DWORD dwMenuData; /* application defined value */
113 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
114 SIZE maxBmpSize; /* Maximum size of the bitmap items */
115 } POPUPMENU, *LPPOPUPMENU;
117 /* internal flags for menu tracking */
119 #define TF_ENDMENU 0x0001
120 #define TF_SUSPENDPOPUP 0x0002
121 #define TF_SKIPREMOVE 0x0004
126 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
127 HMENU hTopMenu; /* initial menu */
128 HWND hOwnerWnd; /* where notifications are sent */
132 #define MENU_MAGIC 0x554d /* 'MU' */
137 /* Internal MENU_TrackMenu() flags */
138 #define TPM_INTERNAL 0xF0000000
139 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
140 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
141 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
143 /* Space between 2 columns */
144 #define MENU_COL_SPACE 4
146 /* top and bottom margins for popup menus */
147 #define MENU_TOP_MARGIN 3
148 #define MENU_BOTTOM_MARGIN 2
150 /* (other menu->FocusedItem values give the position of the focused item) */
151 #define NO_SELECTED_ITEM 0xffff
153 #define MENU_ITEM_TYPE(flags) \
154 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
156 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
157 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
158 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
160 #define IS_SYSTEM_MENU(menu) \
161 (!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
163 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
164 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
165 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
166 MF_POPUP | MF_SYSMENU | MF_HELP)
167 #define STATE_MASK (~TYPE_MASK)
169 #define WIN_ALLOWED_MENU(style) ((style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
171 static SIZE menucharsize;
172 static UINT ODitemheight; /* default owner drawn item height */
174 /* Use global popup window because there's no way 2 menus can
175 * be tracked at the same time. */
176 static HWND top_popup;
178 /* Flag set by EndMenu() to force an exit from menu tracking */
179 static BOOL fEndMenu = FALSE;
181 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
183 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont);
185 /*********************************************************************
186 * menu class descriptor
188 const struct builtin_class_descr MENU_builtin_class =
190 POPUPMENU_CLASS_ATOMA, /* name */
191 CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, /* style */
192 NULL, /* procA (winproc is Unicode only) */
193 PopupMenuWndProc, /* procW */
194 sizeof(HMENU), /* extra */
195 IDC_ARROW, /* cursor */
196 (HBRUSH)(COLOR_MENU+1) /* brush */
200 /***********************************************************************
201 * debug_print_menuitem
203 * Print a menuitem in readable form.
206 #define debug_print_menuitem(pre, mp, post) \
207 do { if (TRACE_ON(menu)) do_debug_print_menuitem(pre, mp, post); } while (0)
209 #define MENUOUT(text) \
210 TRACE("%s%s", (count++ ? "," : ""), (text))
212 #define MENUFLAG(bit,text) \
214 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
217 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
220 static const char * const hbmmenus[] = { "HBMMENU_CALLBACK", "", "HBMMENU_SYSTEM",
221 "HBMMENU_MBAR_RESTORE", "HBMMENU_MBAR_MINIMIZE", "HBMMENU_MBAR_CLOSE",
222 "HBMMENU_MBAR_CLOSE_D", "HBMMENU_MBAR_MINIMIZE_D", "HBMMENU_POPUP_CLOSE",
223 "HBMMENU_POPUP_RESTORE", "HBMMENU_POPUP_MAXIMIZE", "HBMMENU_POPUP_MINIMIZE"};
224 TRACE("%s ", prefix);
226 UINT flags = mp->fType;
227 TRACE( "{ ID=0x%x", mp->wID);
229 TRACE( ", Sub=%p", mp->hSubMenu);
233 MENUFLAG( MFT_SEPARATOR, "sep");
234 MENUFLAG( MFT_OWNERDRAW, "own");
235 MENUFLAG( MFT_BITMAP, "bit");
236 MENUFLAG(MF_POPUP, "pop");
237 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
238 MENUFLAG(MFT_MENUBREAK, "brk");
239 MENUFLAG(MFT_RADIOCHECK, "radio");
240 MENUFLAG(MFT_RIGHTORDER, "rorder");
241 MENUFLAG(MF_SYSMENU, "sys");
242 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
244 TRACE( "+0x%x", flags);
250 MENUFLAG(MFS_GRAYED, "grey");
251 MENUFLAG(MFS_DEFAULT, "default");
252 MENUFLAG(MFS_DISABLED, "dis");
253 MENUFLAG(MFS_CHECKED, "check");
254 MENUFLAG(MFS_HILITE, "hi");
255 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
256 MENUFLAG(MF_MOUSESELECT, "mouse");
258 TRACE( "+0x%x", flags);
261 TRACE( ", Chk=%p", mp->hCheckBit);
263 TRACE( ", Unc=%p", mp->hUnCheckBit);
265 TRACE( ", Text=%s", debugstr_w(mp->text));
267 TRACE( ", ItemData=0x%08lx", mp->dwItemData);
270 if( IS_MAGIC_BITMAP(mp->hbmpItem))
271 TRACE( ", hbitmap=%s", hbmmenus[ (INT_PTR)mp->hbmpItem + 1]);
273 TRACE( ", hbitmap=%p", mp->hbmpItem);
278 TRACE(" %s\n", postfix);
285 /***********************************************************************
288 * Validate the given menu handle and returns the menu structure pointer.
290 static POPUPMENU *MENU_GetMenu(HMENU hMenu)
292 POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
293 if (!menu || menu->wMagic != MENU_MAGIC)
295 WARN("invalid menu handle=%p, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
301 /***********************************************************************
304 * Get the system menu of a window
306 static HMENU get_win_sys_menu( HWND hwnd )
309 WND *win = WIN_GetPtr( hwnd );
310 if (win && win != WND_OTHER_PROCESS && win != WND_DESKTOP)
313 WIN_ReleasePtr( win );
318 /***********************************************************************
321 static HFONT get_menu_font( BOOL bold )
323 static HFONT hMenuFont, hMenuFontBold;
325 HFONT ret = bold ? hMenuFontBold : hMenuFont;
329 NONCLIENTMETRICSW ncm;
332 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
333 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0);
337 ncm.lfMenuFont.lfWeight += 300;
338 if (ncm.lfMenuFont.lfWeight > 1000) ncm.lfMenuFont.lfWeight = 1000;
340 if (!(ret = CreateFontIndirectW( &ncm.lfMenuFont ))) return 0;
341 prev = InterlockedCompareExchangePointer( (void **)(bold ? &hMenuFontBold : &hMenuFont),
345 /* another thread beat us to it */
353 /***********************************************************************
356 static HBITMAP get_arrow_bitmap(void)
358 static HBITMAP arrow_bitmap;
360 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
364 /***********************************************************************
365 * get_down_arrow_bitmap
367 static HBITMAP get_down_arrow_bitmap(void)
369 static HBITMAP arrow_bitmap;
371 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW));
375 /***********************************************************************
376 * get_down_arrow_inactive_bitmap
378 static HBITMAP get_down_arrow_inactive_bitmap(void)
380 static HBITMAP arrow_bitmap;
382 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI));
386 /***********************************************************************
387 * get_up_arrow_bitmap
389 static HBITMAP get_up_arrow_bitmap(void)
391 static HBITMAP arrow_bitmap;
393 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW));
397 /***********************************************************************
398 * get_up_arrow_inactive_bitmap
400 static HBITMAP get_up_arrow_inactive_bitmap(void)
402 static HBITMAP arrow_bitmap;
404 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI));
408 /***********************************************************************
411 * Return the default system menu.
413 static HMENU MENU_CopySysPopup(void)
415 static const WCHAR sysmenuW[] = {'S','Y','S','M','E','N','U',0};
416 HMENU hMenu = LoadMenuW(user32_module, sysmenuW);
419 POPUPMENU* menu = MENU_GetMenu(hMenu);
420 menu->wFlags |= MF_SYSMENU | MF_POPUP;
421 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
424 ERR("Unable to load default system menu\n" );
426 TRACE("returning %p.\n", hMenu );
432 /**********************************************************************
435 * Create a copy of the system menu. System menu in Windows is
436 * a special menu bar with the single entry - system menu popup.
437 * This popup is presented to the outside world as a "system menu".
438 * However, the real system menu handle is sometimes seen in the
439 * WM_MENUSELECT parameters (and Word 6 likes it this way).
441 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
445 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd, hPopupMenu);
446 if ((hMenu = CreateMenu()))
448 POPUPMENU *menu = MENU_GetMenu(hMenu);
449 menu->wFlags = MF_SYSMENU;
450 menu->hWnd = WIN_GetFullHandle( hWnd );
451 TRACE("hWnd %p (hMenu %p)\n", menu->hWnd, hMenu);
454 hPopupMenu = MENU_CopySysPopup();
458 if (GetClassLongW(hWnd, GCL_STYLE) & CS_NOCLOSE)
459 DeleteMenu(hPopupMenu, SC_CLOSE, MF_BYCOMMAND);
461 InsertMenuW( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION,
462 (UINT_PTR)hPopupMenu, NULL );
464 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
465 menu->items[0].fState = 0;
466 if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
468 TRACE("hMenu=%p (hPopup %p)\n", hMenu, hPopupMenu );
471 DestroyMenu( hMenu );
473 ERR("failed to load system menu!\n");
478 /***********************************************************************
479 * MENU_InitSysMenuPopup
481 * Grey the appropriate items in System menu.
483 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
487 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
488 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
489 gray = ((style & WS_MAXIMIZE) != 0);
490 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
491 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
492 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
493 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
494 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
495 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
496 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
497 gray = (clsStyle & CS_NOCLOSE) != 0;
499 /* The menu item must keep its state if it's disabled */
501 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
505 /******************************************************************************
507 * UINT MENU_GetStartOfNextColumn(
510 *****************************************************************************/
512 static UINT MENU_GetStartOfNextColumn(
515 POPUPMENU *menu = MENU_GetMenu(hMenu);
519 return NO_SELECTED_ITEM;
521 i = menu->FocusedItem + 1;
522 if( i == NO_SELECTED_ITEM )
525 for( ; i < menu->nItems; ++i ) {
526 if (menu->items[i].fType & MF_MENUBARBREAK)
530 return NO_SELECTED_ITEM;
534 /******************************************************************************
536 * UINT MENU_GetStartOfPrevColumn(
539 *****************************************************************************/
541 static UINT MENU_GetStartOfPrevColumn(
544 POPUPMENU *menu = MENU_GetMenu(hMenu);
548 return NO_SELECTED_ITEM;
550 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
551 return NO_SELECTED_ITEM;
553 /* Find the start of the column */
555 for(i = menu->FocusedItem; i != 0 &&
556 !(menu->items[i].fType & MF_MENUBARBREAK);
560 return NO_SELECTED_ITEM;
562 for(--i; i != 0; --i) {
563 if (menu->items[i].fType & MF_MENUBARBREAK)
567 TRACE("ret %d.\n", i );
574 /***********************************************************************
577 * Find a menu item. Return a pointer on the item, and modifies *hmenu
578 * in case the item was in a sub-menu.
580 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
583 MENUITEM *fallback = NULL;
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 if ((UINT_PTR)item->hSubMenu == *nPos)
607 fallback = item; /* fallback to this item if nothing else found */
609 else if (item->wID == *nPos)
619 /***********************************************************************
622 * Find a Sub menu. Return the position of the submenu, and modifies
623 * *hmenu in case it is found in another sub-menu.
624 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
626 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
631 if (((*hmenu)==(HMENU)0xffff) ||
632 (!(menu = MENU_GetMenu(*hmenu))))
633 return NO_SELECTED_ITEM;
635 for (i = 0; i < menu->nItems; i++, item++) {
636 if(!(item->fType & MF_POPUP)) continue;
637 if (item->hSubMenu == hSubTarget) {
641 HMENU hsubmenu = item->hSubMenu;
642 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
643 if (pos != NO_SELECTED_ITEM) {
649 return NO_SELECTED_ITEM;
652 /***********************************************************************
655 static void MENU_FreeItemData( MENUITEM* item )
658 HeapFree( GetProcessHeap(), 0, item->text );
661 /***********************************************************************
662 * MENU_AdjustMenuItemRect
664 * Adjust menu item rectangle according to scrolling state.
667 MENU_AdjustMenuItemRect(const POPUPMENU *menu, LPRECT rect)
669 if (menu->bScrolling)
671 UINT arrow_bitmap_width, arrow_bitmap_height;
674 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
675 arrow_bitmap_width = bmp.bmWidth;
676 arrow_bitmap_height = bmp.bmHeight;
677 rect->top += arrow_bitmap_height - menu->nScrollPos;
678 rect->bottom += arrow_bitmap_height - menu->nScrollPos;
683 /***********************************************************************
684 * MENU_FindItemByCoords
686 * Find the item at the specified coordinates (screen coords). Does
687 * not work for child windows and therefore should not be called for
688 * an arbitrary system menu.
690 static MENUITEM *MENU_FindItemByCoords( const POPUPMENU *menu,
691 POINT pt, UINT *pos )
698 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
699 pt.x -= wrect.left;pt.y -= wrect.top;
701 for (i = 0; i < menu->nItems; i++, item++)
704 MENU_AdjustMenuItemRect(menu, &rect);
705 if ((pt.x >= rect.left) && (pt.x < rect.right) &&
706 (pt.y >= rect.top) && (pt.y < rect.bottom))
716 /***********************************************************************
719 * Find the menu item selected by a key press.
720 * Return item id, -1 if none, -2 if we should close the menu.
722 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
723 WCHAR key, BOOL forceMenuChar )
725 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)key, key, hmenu );
727 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
731 POPUPMENU *menu = MENU_GetMenu( hmenu );
732 MENUITEM *item = menu->items;
739 for (i = 0; i < menu->nItems; i++, item++)
743 WCHAR *p = item->text - 2;
746 p = strchrW (p + 2, '&');
748 while (p != NULL && p [1] == '&');
749 if (p && (toupperW(p[1]) == toupperW(key))) return i;
753 menuchar = SendMessageW( hwndOwner, WM_MENUCHAR,
754 MAKEWPARAM( key, menu->wFlags ), (LPARAM)hmenu );
755 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
756 if (HIWORD(menuchar) == 1) return (UINT)(-2);
762 /***********************************************************************
763 * MENU_GetBitmapItemSize
765 * Get the size of a bitmap item.
767 static void MENU_GetBitmapItemSize( MENUITEM *lpitem, SIZE *size,
771 HBITMAP bmp = lpitem->hbmpItem;
773 size->cx = size->cy = 0;
775 /* check if there is a magic menu item associated with this item */
776 switch( (INT_PTR) bmp )
778 case (INT_PTR)HBMMENU_CALLBACK:
780 MEASUREITEMSTRUCT measItem;
781 measItem.CtlType = ODT_MENU;
783 measItem.itemID = lpitem->wID;
784 measItem.itemWidth = lpitem->rect.right - lpitem->rect.left;
785 measItem.itemHeight = lpitem->rect.bottom - lpitem->rect.top;
786 measItem.itemData = lpitem->dwItemData;
787 SendMessageW( hwndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
788 size->cx = measItem.itemWidth;
789 size->cy = measItem.itemHeight;
793 case (INT_PTR)HBMMENU_SYSTEM:
794 if (lpitem->dwItemData)
796 bmp = (HBITMAP)lpitem->dwItemData;
800 case (INT_PTR)HBMMENU_MBAR_RESTORE:
801 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
802 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
803 case (INT_PTR)HBMMENU_MBAR_CLOSE:
804 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
805 size->cx = GetSystemMetrics( SM_CYMENU ) - 4;
808 case (INT_PTR)HBMMENU_POPUP_CLOSE:
809 case (INT_PTR)HBMMENU_POPUP_RESTORE:
810 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
811 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
812 FIXME("Magic %p not implemented\n", bmp );
815 if (GetObjectW(bmp, sizeof(bm), &bm ))
817 size->cx = bm.bmWidth;
818 size->cy = bm.bmHeight;
822 /***********************************************************************
823 * MENU_DrawBitmapItem
825 * Draw a bitmap item.
827 static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect,
828 HMENU hmenu, HWND hwndOwner, UINT odaction, BOOL menuBar)
834 int w = rect->right - rect->left;
835 int h = rect->bottom - rect->top;
838 HBITMAP hbmToDraw = lpitem->hbmpItem;
841 /* Check if there is a magic menu item associated with this item */
842 if (IS_MAGIC_BITMAP(hbmToDraw))
847 switch((INT_PTR)hbmToDraw)
849 case (INT_PTR)HBMMENU_SYSTEM:
850 if (lpitem->dwItemData)
852 bmp = (HBITMAP)lpitem->dwItemData;
853 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
857 static HBITMAP hBmpSysMenu;
859 if (!hBmpSysMenu) hBmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
861 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
862 /* only use right half of the bitmap */
863 bmp_xoffset = bm.bmWidth / 2;
864 bm.bmWidth -= bmp_xoffset;
867 case (INT_PTR)HBMMENU_MBAR_RESTORE:
868 flags = DFCS_CAPTIONRESTORE;
870 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
871 flags = DFCS_CAPTIONMIN;
873 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
874 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
876 case (INT_PTR)HBMMENU_MBAR_CLOSE:
877 flags = DFCS_CAPTIONCLOSE;
879 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
880 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
882 case (INT_PTR)HBMMENU_CALLBACK:
884 DRAWITEMSTRUCT drawItem;
885 drawItem.CtlType = ODT_MENU;
887 drawItem.itemID = lpitem->wID;
888 drawItem.itemAction = odaction;
889 drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
890 drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
891 drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
892 drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
893 drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
894 drawItem.hwndItem = (HWND)hmenu;
896 drawItem.itemData = lpitem->dwItemData;
897 drawItem.rcItem = *rect;
898 SendMessageW( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem);
902 case (INT_PTR)HBMMENU_POPUP_CLOSE:
903 case (INT_PTR)HBMMENU_POPUP_RESTORE:
904 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
905 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
907 FIXME("Magic %p not implemented\n", hbmToDraw);
911 InflateRect( &r, -1, -1 );
912 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
913 DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
917 if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
920 hdcMem = CreateCompatibleDC( hdc );
921 SelectObject( hdcMem, bmp );
923 /* handle fontsize > bitmap_height */
924 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
926 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
927 if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem)
928 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
929 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
934 /***********************************************************************
937 * Calculate the size of the menu item and store it in lpitem->rect.
939 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
940 INT orgX, INT orgY, BOOL menuBar, POPUPMENU* lppop )
943 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
944 UINT arrow_bitmap_width;
948 TRACE("dc=%p owner=%p (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
949 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
950 (menuBar ? " (MenuBar)" : ""));
952 GetObjectW( get_arrow_bitmap(), sizeof(bm), &bm );
953 arrow_bitmap_width = bm.bmWidth;
955 /* not done in Menu_Init: GetDialogBaseUnits() breaks there */
956 if( !menucharsize.cx ) {
957 menucharsize.cx = GdiGetCharDimensions( hdc, NULL, &menucharsize.cy );
958 /* Win95/98/ME will use menucharsize.cy here. Testing is possible
959 * but it is unlikely an application will depend on that */
960 ODitemheight = HIWORD( GetDialogBaseUnits());
963 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
965 if (lpitem->fType & MF_OWNERDRAW)
967 MEASUREITEMSTRUCT mis;
968 mis.CtlType = ODT_MENU;
970 mis.itemID = lpitem->wID;
971 mis.itemData = lpitem->dwItemData;
972 mis.itemHeight = ODitemheight;
974 SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
975 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
976 * width of a menufont character to the width of an owner-drawn menu.
978 lpitem->rect.right += mis.itemWidth + 2 * menucharsize.cx;
980 /* under at least win95 you seem to be given a standard
981 height for the menu and the height value is ignored */
982 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENUSIZE);
984 lpitem->rect.bottom += mis.itemHeight;
986 TRACE("id=%04x size=%ldx%ld\n",
987 lpitem->wID, lpitem->rect.right-lpitem->rect.left,
988 lpitem->rect.bottom-lpitem->rect.top);
992 if (lpitem->fType & MF_SEPARATOR)
994 lpitem->rect.bottom += GetSystemMetrics( SM_CYMENUSIZE)/2;
996 lpitem->rect.right += arrow_bitmap_width + menucharsize.cx;
1003 if (lpitem->hbmpItem) {
1006 MENU_GetBitmapItemSize(lpitem, &size, hwndOwner);
1007 /* Keep the size of the bitmap in callback mode to be able
1008 * to draw it correctly */
1009 lpitem->bmpsize = size;
1010 lppop->maxBmpSize.cx = max( lppop->maxBmpSize.cx, size.cx);
1011 lppop->maxBmpSize.cy = max( lppop->maxBmpSize.cy, size.cy);
1012 lpitem->rect.right += size.cx;
1013 itemheight = size.cy;
1014 if (lppop->dwStyle & MNS_CHECKORBMP)
1015 lpitem->rect.right += check_bitmap_width;
1017 lpitem->rect.right += 2 * check_bitmap_width;
1019 lpitem->rect.right += 2 * check_bitmap_width;
1020 if (lpitem->fType & MF_POPUP)
1021 lpitem->rect.right += arrow_bitmap_width;
1022 } else if (lpitem->hbmpItem) { /* menuBar */
1025 MENU_GetBitmapItemSize( lpitem, &size, hwndOwner );
1026 lpitem->bmpsize = size;
1027 lpitem->rect.right += size.cx;
1028 if( lpitem->text) lpitem->rect.right += 2;
1029 itemheight = size.cy;
1032 /* it must be a text item - unless it's the system menu */
1033 if (!(lpitem->fType & MF_SYSMENU) && lpitem->text) {
1034 RECT rc = lpitem->rect;
1035 LONG txtheight, txtwidth;
1039 txtheight = DrawTextW( hdc, lpitem->text, -1, &rc,
1040 DT_SINGLELINE|DT_CALCRECT);
1041 lpitem->rect.right += rc.right - rc.left;
1042 itemheight = max( max( itemheight, txtheight),
1043 GetSystemMetrics( SM_CYMENU) - 1);
1044 lpitem->rect.right += 2 * menucharsize.cx;
1046 if ((p = strchrW( lpitem->text, '\t' )) != NULL) {
1049 int n = (int)( p - lpitem->text);
1050 /* Item contains a tab (only meaningful in popup menus) */
1051 /* get text size before the tab */
1052 txtheight = DrawTextW( hdc, lpitem->text, n, &rc,
1053 DT_SINGLELINE|DT_CALCRECT);
1054 txtwidth = rc.right - rc.left;
1055 p += 1; /* advance past the Tab */
1056 /* get text size after the tab */
1057 tmpheight = DrawTextW( hdc, p, -1, &tmprc,
1058 DT_SINGLELINE|DT_CALCRECT);
1059 lpitem->xTab = menucharsize.cx +
1060 4 + check_bitmap_width + lpitem->bmpsize.cx + txtwidth;
1061 txtheight = max( txtheight, tmpheight);
1062 txtwidth += menucharsize.cx + /* space for the tab */
1063 tmprc.right - tmprc.left; /* space for the short cut */
1065 txtheight = DrawTextW( hdc, lpitem->text, -1, &rc,
1066 DT_SINGLELINE|DT_CALCRECT);
1067 txtwidth = rc.right - rc.left;
1068 if (strchrW( lpitem->text, '\b' ))
1069 lpitem->rect.right += menucharsize.cx;
1070 lpitem->xTab = 4 + check_bitmap_width + lpitem->bmpsize.cx +
1073 lpitem->rect.right += 2 + txtwidth;
1074 itemheight = max( itemheight,
1075 max( txtheight + 2, menucharsize.cy + 4));
1077 } else if( menuBar) {
1078 itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1);
1080 lpitem->rect.bottom += itemheight;
1081 TRACE("%s\n", wine_dbgstr_rect( &lpitem->rect));
1085 /***********************************************************************
1086 * MENU_GetMaxPopupHeight
1089 MENU_GetMaxPopupHeight(LPPOPUPMENU lppop)
1092 return lppop->cyMax;
1093 return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER);
1097 /***********************************************************************
1098 * MENU_PopupMenuCalcSize
1100 * Calculate the size of a popup menu.
1102 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
1107 int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
1109 lppop->Width = lppop->Height = 0;
1110 if (lppop->nItems == 0) return;
1113 SelectObject( hdc, get_menu_font(FALSE));
1118 lppop->maxBmpSize.cx = 0;
1119 lppop->maxBmpSize.cy = 0;
1121 while (start < lppop->nItems)
1123 lpitem = &lppop->items[start];
1125 if( lpitem->fType & MF_MENUBREAK)
1126 orgX += MENU_COL_SPACE;
1127 orgY = MENU_TOP_MARGIN;
1129 maxTab = maxTabWidth = 0;
1130 /* Parse items until column break or end of menu */
1131 for (i = start; i < lppop->nItems; i++, lpitem++)
1134 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1136 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE, lppop );
1138 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
1139 maxX = max( maxX, lpitem->rect.right );
1140 orgY = lpitem->rect.bottom;
1141 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1143 maxTab = max( maxTab, lpitem->xTab );
1144 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
1148 /* Finish the column (set all items to the largest width found) */
1149 maxX = max( maxX, maxTab + maxTabWidth );
1150 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
1152 lpitem->rect.right = maxX;
1153 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1154 lpitem->xTab = maxTab;
1157 lppop->Height = max( lppop->Height, orgY );
1160 lppop->Width = maxX;
1162 /* space for 3d border */
1163 lppop->Height += MENU_BOTTOM_MARGIN;
1166 /* Adjust popup height if it exceeds maximum */
1167 maxHeight = MENU_GetMaxPopupHeight(lppop);
1168 lppop->nTotalHeight = lppop->Height - MENU_TOP_MARGIN;
1169 if (lppop->Height >= maxHeight)
1171 lppop->Height = maxHeight;
1172 lppop->bScrolling = TRUE;
1176 lppop->bScrolling = FALSE;
1179 ReleaseDC( 0, hdc );
1183 /***********************************************************************
1184 * MENU_MenuBarCalcSize
1186 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1187 * height is off by 1 pixel which causes lengthy window relocations when
1188 * active document window is maximized/restored.
1190 * Calculate the size of the menu bar.
1192 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1193 LPPOPUPMENU lppop, HWND hwndOwner )
1196 int start, i, orgX, orgY, maxY, helpPos;
1198 if ((lprect == NULL) || (lppop == NULL)) return;
1199 if (lppop->nItems == 0) return;
1200 TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
1201 lppop->Width = lprect->right - lprect->left;
1203 maxY = lprect->top+1;
1206 lppop->maxBmpSize.cx = 0;
1207 lppop->maxBmpSize.cy = 0;
1208 while (start < lppop->nItems)
1210 lpitem = &lppop->items[start];
1211 orgX = lprect->left;
1214 /* Parse items until line break or end of menu */
1215 for (i = start; i < lppop->nItems; i++, lpitem++)
1217 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
1219 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1221 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY );
1222 debug_print_menuitem (" item: ", lpitem, "");
1223 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE, lppop );
1225 if (lpitem->rect.right > lprect->right)
1227 if (i != start) break;
1228 else lpitem->rect.right = lprect->right;
1230 maxY = max( maxY, lpitem->rect.bottom );
1231 orgX = lpitem->rect.right;
1234 /* Finish the line (set all items to the largest height found) */
1235 while (start < i) lppop->items[start++].rect.bottom = maxY;
1238 lprect->bottom = maxY;
1239 lppop->Height = lprect->bottom - lprect->top;
1241 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1242 /* the last item (if several lines, only move the last line) */
1243 lpitem = &lppop->items[lppop->nItems-1];
1244 orgY = lpitem->rect.top;
1245 orgX = lprect->right;
1246 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1247 if ( (helpPos==-1) || (helpPos>i) )
1249 if (lpitem->rect.top != orgY) break; /* Other line */
1250 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1251 lpitem->rect.left += orgX - lpitem->rect.right;
1252 lpitem->rect.right = orgX;
1253 orgX = lpitem->rect.left;
1258 /***********************************************************************
1259 * MENU_DrawScrollArrows
1261 * Draw scroll arrows.
1264 MENU_DrawScrollArrows(LPPOPUPMENU lppop, HDC hdc)
1266 HDC hdcMem = CreateCompatibleDC(hdc);
1267 HBITMAP hOrigBitmap;
1268 UINT arrow_bitmap_width, arrow_bitmap_height;
1272 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
1273 arrow_bitmap_width = bmp.bmWidth;
1274 arrow_bitmap_height = bmp.bmHeight;
1277 if (lppop->nScrollPos)
1278 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
1280 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
1283 rect.right = lppop->Width;
1284 rect.bottom = arrow_bitmap_height;
1285 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1286 BitBlt(hdc, (lppop->Width - arrow_bitmap_width) / 2, 0,
1287 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1288 rect.top = lppop->Height - arrow_bitmap_height;
1289 rect.bottom = lppop->Height;
1290 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1291 if (lppop->nScrollPos < lppop->nTotalHeight - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
1292 SelectObject(hdcMem, get_down_arrow_bitmap());
1294 SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
1295 BitBlt(hdc, (lppop->Width - arrow_bitmap_width) / 2,
1296 lppop->Height - arrow_bitmap_height,
1297 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1298 SelectObject(hdcMem, hOrigBitmap);
1303 /***********************************************************************
1306 * Draws the popup-menu arrow.
1308 static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_bitmap_width,
1309 UINT arrow_bitmap_height)
1311 HDC hdcMem = CreateCompatibleDC( hdc );
1312 HBITMAP hOrigBitmap;
1314 hOrigBitmap = SelectObject( hdcMem, get_arrow_bitmap() );
1315 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1316 (rect.top + rect.bottom - arrow_bitmap_height) / 2,
1317 arrow_bitmap_width, arrow_bitmap_height,
1318 hdcMem, 0, 0, SRCCOPY );
1319 SelectObject( hdcMem, hOrigBitmap );
1322 /***********************************************************************
1325 * Draw a single menu item.
1327 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1328 UINT height, BOOL menuBar, UINT odaction )
1331 BOOL flat_menu = FALSE;
1333 UINT arrow_bitmap_width = 0, arrow_bitmap_height = 0;
1334 POPUPMENU *menu = MENU_GetMenu(hmenu);
1337 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1341 GetObjectW( get_arrow_bitmap(), sizeof(bmp), &bmp );
1342 arrow_bitmap_width = bmp.bmWidth;
1343 arrow_bitmap_height = bmp.bmHeight;
1346 if (lpitem->fType & MF_SYSMENU)
1348 if( !IsIconic(hwnd) )
1349 NC_DrawSysButton( hwnd, hdc, lpitem->fState & (MF_HILITE | MF_MOUSESELECT) );
1353 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1354 bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
1358 if (lpitem->fState & MF_HILITE)
1360 if(menuBar && !flat_menu) {
1361 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1362 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1364 if(lpitem->fState & MF_GRAYED)
1365 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1367 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1368 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1373 if (lpitem->fState & MF_GRAYED)
1374 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1376 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1377 SetBkColor( hdc, GetSysColor( bkgnd ) );
1380 if (lpitem->fType & MF_OWNERDRAW)
1383 ** Experimentation under Windows reveals that an owner-drawn
1384 ** menu is given the rectangle which includes the space it requested
1385 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1386 ** and a popup-menu arrow. This is the value of lpitem->rect.
1387 ** Windows will leave all drawing to the application except for
1388 ** the popup-menu arrow. Windows always draws that itself, after
1389 ** the menu owner has finished drawing.
1393 dis.CtlType = ODT_MENU;
1395 dis.itemID = lpitem->wID;
1396 dis.itemData = lpitem->dwItemData;
1398 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1399 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED|ODS_DISABLED;
1400 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1401 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1402 dis.hwndItem = (HWND)hmenu;
1404 dis.rcItem = lpitem->rect;
1405 MENU_AdjustMenuItemRect(MENU_GetMenu(hmenu), &dis.rcItem);
1406 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1407 "hwndItem=%p, hdc=%p, rcItem=%s\n", hwndOwner,
1408 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1409 dis.hDC, wine_dbgstr_rect( &dis.rcItem));
1410 SendMessageW( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1411 /* Draw the popup-menu arrow */
1412 if (lpitem->fType & MF_POPUP)
1413 draw_popup_arrow( hdc, rect, arrow_bitmap_width,
1414 arrow_bitmap_height);
1418 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->rect));
1420 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1422 rect = lpitem->rect;
1423 MENU_AdjustMenuItemRect(MENU_GetMenu(hmenu), &rect);
1425 if (lpitem->fState & MF_HILITE)
1429 InflateRect (&rect, -1, -1);
1430 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT));
1431 InflateRect (&rect, 1, 1);
1432 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1437 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1439 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1443 FillRect( hdc, &rect, GetSysColorBrush(bkgnd) );
1445 SetBkMode( hdc, TRANSPARENT );
1447 /* vertical separator */
1448 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1454 rc.bottom = height - 3;
1457 oldPen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_BTNSHADOW) );
1458 MoveToEx( hdc, rc.left, rc.top, NULL );
1459 LineTo( hdc, rc.left, rc.bottom );
1460 SelectObject( hdc, oldPen );
1463 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1466 /* horizontal separator */
1467 if (lpitem->fType & MF_SEPARATOR)
1474 rc.top = ( rc.top + rc.bottom) / 2;
1477 oldPen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_BTNSHADOW) );
1478 MoveToEx( hdc, rc.left, rc.top, NULL );
1479 LineTo( hdc, rc.right, rc.top );
1480 SelectObject( hdc, oldPen );
1483 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1487 /* helper lines for debugging */
1488 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1489 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1490 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1491 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1494 if (lpitem->hbmpItem) {
1495 /* calculate the bitmap rectangle in coordinates relative
1496 * to the item rectangle */
1498 if( lpitem->hbmpItem == HBMMENU_CALLBACK)
1501 bmprc.left = lpitem->text ? menucharsize.cx : 0;
1504 if( !(menu->dwStyle & MNS_NOCHECK))
1505 bmprc.left += GetSystemMetrics( SM_CXMENUCHECK);
1507 bmprc.right = bmprc.left + lpitem->bmpsize.cx;
1508 if( menuBar && !(lpitem->hbmpItem == HBMMENU_CALLBACK))
1511 bmprc.top = (lpitem->rect.bottom - lpitem->rect.top -
1512 lpitem->bmpsize.cy) / 2;
1513 bmprc.bottom = bmprc.top + lpitem->bmpsize.cy;
1519 INT y = rect.top + rect.bottom;
1521 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1522 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1524 if (lpitem->hbmpItem)
1526 POPUPMENU *menu = MENU_GetMenu(hmenu);
1527 if (menu->dwStyle & MNS_CHECKORBMP)
1528 rc.left += menu->maxBmpSize.cx - check_bitmap_width;
1530 rc.left += menu->maxBmpSize.cx;
1532 /* Draw the check mark
1535 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1537 bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
1538 if (bm) /* we have a custom bitmap */
1540 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 );
1547 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1550 HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1551 HDC hdcMem = CreateCompatibleDC( hdc );
1552 SelectObject( hdcMem, bm );
1553 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
1554 DrawFrameControl( hdcMem, &r, DFC_MENU,
1555 (lpitem->fType & MFT_RADIOCHECK) ?
1556 DFCS_MENUBULLET : DFCS_MENUCHECK );
1557 BitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom,
1558 hdcMem, 0, 0, SRCCOPY );
1562 if (lpitem->hbmpItem)
1565 /* some applications make this assumption on the DC's origin */
1566 SetViewportOrgEx( hdc, lpitem->rect.left, lpitem->rect.top, &origorg);
1567 MENU_DrawBitmapItem(hdc, lpitem, &bmprc, hmenu, hwndOwner,
1569 SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1571 /* Draw the popup-menu arrow */
1572 if (lpitem->fType & MF_POPUP)
1573 draw_popup_arrow( hdc, rect, arrow_bitmap_width,
1574 arrow_bitmap_height);
1576 rect.left += check_bitmap_width;
1577 rect.right -= arrow_bitmap_width;
1579 else if( lpitem->hbmpItem)
1580 { /* Draw the bitmap */
1583 SetViewportOrgEx( hdc, lpitem->rect.left, lpitem->rect.top, &origorg);
1584 MENU_DrawBitmapItem( hdc, lpitem, &bmprc, hmenu, hwndOwner,
1586 SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1588 /* process text if present */
1594 UINT uFormat = (menuBar) ?
1595 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1596 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1598 if ( lpitem->fState & MFS_DEFAULT )
1600 hfontOld = SelectObject( hdc, get_menu_font(TRUE) );
1604 if( lpitem->hbmpItem)
1605 rect.left += lpitem->bmpsize.cx;
1606 if( !(lpitem->hbmpItem == HBMMENU_CALLBACK))
1607 rect.left += menucharsize.cx;
1608 rect.right -= menucharsize.cx;
1611 for (i = 0; lpitem->text[i]; i++)
1612 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1615 if(lpitem->fState & MF_GRAYED)
1617 if (!(lpitem->fState & MF_HILITE) )
1619 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1620 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1621 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1622 --rect.left; --rect.top; --rect.right; --rect.bottom;
1624 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1627 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
1629 /* paint the shortcut text */
1630 if (!menuBar && lpitem->text[i]) /* There's a tab or flush-right char */
1632 if (lpitem->text[i] == '\t')
1634 rect.left = lpitem->xTab;
1635 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1639 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1642 if(lpitem->fState & MF_GRAYED)
1644 if (!(lpitem->fState & MF_HILITE) )
1646 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1647 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1648 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1649 --rect.left; --rect.top; --rect.right; --rect.bottom;
1651 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1653 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1657 SelectObject (hdc, hfontOld);
1662 /***********************************************************************
1663 * MENU_DrawPopupMenu
1665 * Paint a popup menu.
1667 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1669 HBRUSH hPrevBrush = 0;
1672 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
1674 GetClientRect( hwnd, &rect );
1676 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1677 && (SelectObject( hdc, get_menu_font(FALSE))))
1681 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1683 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1687 BOOL flat_menu = FALSE;
1689 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1691 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW));
1693 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1695 menu = MENU_GetMenu( hmenu );
1697 /* draw menu items */
1698 if (menu && menu->nItems)
1703 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1704 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1705 menu->Height, FALSE, ODA_DRAWENTIRE );
1709 /* draw scroll arrows */
1710 if (menu->bScrolling)
1711 MENU_DrawScrollArrows(menu, hdc);
1714 SelectObject( hdc, hPrevBrush );
1719 /***********************************************************************
1722 * Paint a menu bar. Returns the height of the menu bar.
1723 * called from [windows/nonclient.c]
1725 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1730 HMENU hMenu = GetMenu(hwnd);
1732 lppop = MENU_GetMenu( hMenu );
1733 if (lppop == NULL || lprect == NULL)
1735 return GetSystemMetrics(SM_CYMENU);
1740 hfontOld = SelectObject( hDC, get_menu_font(FALSE));
1742 if (lppop->Height == 0)
1743 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1745 lprect->bottom = lprect->top + lppop->Height;
1747 if (hfontOld) SelectObject( hDC, hfontOld);
1748 return lppop->Height;
1751 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
1755 /***********************************************************************
1758 * Display a popup menu.
1760 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1761 INT x, INT y, INT xanchor, INT yanchor )
1766 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1767 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1769 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1770 if (menu->FocusedItem != NO_SELECTED_ITEM)
1772 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1773 menu->FocusedItem = NO_SELECTED_ITEM;
1776 /* store the owner for DrawItem */
1777 menu->hwndOwner = hwndOwner;
1779 menu->nScrollPos = 0;
1780 MENU_PopupMenuCalcSize( menu, hwndOwner );
1782 /* adjust popup menu pos so that it fits within the desktop */
1784 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1785 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1787 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1790 x -= width - xanchor;
1791 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1792 x = GetSystemMetrics(SM_CXSCREEN) - width;
1796 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1799 y -= height + yanchor;
1800 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1801 y = GetSystemMetrics(SM_CYSCREEN) - height;
1805 /* NOTE: In Windows, top menu popup is not owned. */
1806 menu->hWnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL,
1807 WS_POPUP, x, y, width, height,
1808 hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
1810 if( !menu->hWnd ) return FALSE;
1811 if (!top_popup) top_popup = menu->hWnd;
1813 /* Display the window */
1815 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1816 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1817 UpdateWindow( menu->hWnd );
1822 /***********************************************************************
1823 * MENU_EnsureMenuItemVisible
1826 MENU_EnsureMenuItemVisible(LPPOPUPMENU lppop, UINT wIndex, HDC hdc)
1828 if (lppop->bScrolling)
1830 MENUITEM *item = &lppop->items[wIndex];
1831 UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
1832 UINT nOldPos = lppop->nScrollPos;
1834 UINT arrow_bitmap_height;
1837 GetClientRect(lppop->hWnd, &rc);
1839 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
1840 arrow_bitmap_height = bmp.bmHeight;
1842 rc.top += arrow_bitmap_height;
1843 rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
1845 nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
1846 if (item->rect.bottom > lppop->nScrollPos + nMaxHeight)
1849 lppop->nScrollPos = item->rect.bottom - nMaxHeight;
1850 ScrollWindow(lppop->hWnd, 0, nOldPos - lppop->nScrollPos, &rc, &rc);
1851 MENU_DrawScrollArrows(lppop, hdc);
1853 else if (item->rect.top - MENU_TOP_MARGIN < lppop->nScrollPos)
1855 lppop->nScrollPos = item->rect.top - MENU_TOP_MARGIN;
1856 ScrollWindow(lppop->hWnd, 0, nOldPos - lppop->nScrollPos, &rc, &rc);
1857 MENU_DrawScrollArrows(lppop, hdc);
1863 /***********************************************************************
1866 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1867 BOOL sendMenuSelect, HMENU topmenu )
1872 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1874 lppop = MENU_GetMenu( hmenu );
1875 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
1877 if (lppop->FocusedItem == wIndex) return;
1878 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1879 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1880 if (!top_popup) top_popup = lppop->hWnd;
1882 SelectObject( hdc, get_menu_font(FALSE));
1884 /* Clear previous highlighted item */
1885 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1887 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1888 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1889 lppop->Height, !(lppop->wFlags & MF_POPUP),
1893 /* Highlight new item (if any) */
1894 lppop->FocusedItem = wIndex;
1895 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1897 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1898 lppop->items[wIndex].fState |= MF_HILITE;
1899 MENU_EnsureMenuItemVisible(lppop, wIndex, hdc);
1900 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1901 &lppop->items[wIndex], lppop->Height,
1902 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1906 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1907 SendMessageW( hwndOwner, WM_MENUSELECT,
1908 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1909 ip->fType | ip->fState |
1910 (lppop->wFlags & MF_SYSMENU)), (LPARAM)hmenu);
1913 else if (sendMenuSelect) {
1916 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1917 POPUPMENU *ptm = MENU_GetMenu( topmenu );
1918 MENUITEM *ip = &ptm->items[pos];
1919 SendMessageW( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1920 ip->fType | ip->fState |
1921 (ptm->wFlags & MF_SYSMENU)), (LPARAM)topmenu);
1925 ReleaseDC( lppop->hWnd, hdc );
1929 /***********************************************************************
1930 * MENU_MoveSelection
1932 * Moves currently selected item according to the offset parameter.
1933 * If there is no selection then it should select the last item if
1934 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1936 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1941 TRACE("hwnd=%p hmenu=%p off=0x%04x\n", hwndOwner, hmenu, offset);
1943 menu = MENU_GetMenu( hmenu );
1944 if ((!menu) || (!menu->items)) return;
1946 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1948 if( menu->nItems == 1 ) return; else
1949 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1951 if (!(menu->items[i].fType & MF_SEPARATOR))
1953 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1958 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1959 i >= 0 && i < menu->nItems ; i += offset)
1960 if (!(menu->items[i].fType & MF_SEPARATOR))
1962 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1968 /**********************************************************************
1971 * Set an item's flags, id and text ptr. Called by InsertMenu() and
1974 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id,
1977 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1978 TRACE("flags=%x str=%p\n", flags, str);
1980 if (IS_STRING_ITEM(flags))
1982 LPWSTR prevText = item->text;
1985 flags |= MF_SEPARATOR;
1991 /* Item beginning with a backspace is a help item */
1997 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1999 strcpyW( text, str );
2002 item->hbmpItem = NULL;
2003 HeapFree( GetProcessHeap(), 0, prevText );
2005 else if(( flags & MFT_BITMAP)) {
2006 item->hbmpItem = HBITMAP_32(LOWORD(str));
2007 /* setting bitmap clears text */
2008 HeapFree( GetProcessHeap(), 0, item->text );
2012 if (flags & MF_OWNERDRAW)
2013 item->dwItemData = (DWORD_PTR)str;
2015 item->dwItemData = 0;
2017 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != (HMENU)id) )
2018 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
2020 if (flags & MF_POPUP)
2022 POPUPMENU *menu = MENU_GetMenu((HMENU)id);
2023 if (menu) menu->wFlags |= MF_POPUP;
2035 if (flags & MF_POPUP) item->hSubMenu = (HMENU)id;
2037 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
2038 flags |= MF_POPUP; /* keep popup */
2040 item->fType = flags & TYPE_MASK;
2041 item->fState = (flags & STATE_MASK) &
2042 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
2044 /* Don't call SetRectEmpty here! */
2046 debug_print_menuitem("MENU_SetItemData to : ", item, "");
2051 /**********************************************************************
2054 * Insert (allocate) a new item into a menu.
2056 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
2061 if (!(menu = MENU_GetMenu(hMenu)))
2064 /* Find where to insert new item */
2066 if (flags & MF_BYPOSITION) {
2067 if (pos > menu->nItems)
2070 if (!MENU_FindItem( &hMenu, &pos, flags ))
2073 if (!(menu = MENU_GetMenu( hMenu )))
2078 /* Create new items array */
2080 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
2083 WARN("allocation failed\n" );
2086 if (menu->nItems > 0)
2088 /* Copy the old array into the new one */
2089 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
2090 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
2091 (menu->nItems-pos)*sizeof(MENUITEM) );
2092 HeapFree( GetProcessHeap(), 0, menu->items );
2094 menu->items = newItems;
2096 memset( &newItems[pos], 0, sizeof(*newItems) );
2097 menu->Height = 0; /* force size recalculate */
2098 return &newItems[pos];
2102 /**********************************************************************
2103 * MENU_ParseResource
2105 * Parse a standard menu resource and add items to the menu.
2106 * Return a pointer to the end of the resource.
2108 * NOTE: flags is equivalent to the mtOption field
2110 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
2117 flags = GET_WORD(res);
2118 res += sizeof(WORD);
2119 if (!(flags & MF_POPUP))
2122 res += sizeof(WORD);
2125 if (!unicode) res += strlen(str) + 1;
2126 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
2127 if (flags & MF_POPUP)
2129 HMENU hSubMenu = CreatePopupMenu();
2130 if (!hSubMenu) return NULL;
2131 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
2133 if (!unicode) AppendMenuA( hMenu, flags, (UINT_PTR)hSubMenu, str );
2134 else AppendMenuW( hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str );
2136 else /* Not a popup */
2138 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
2139 else AppendMenuW( hMenu, flags, id,
2140 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
2142 } while (!(flags & MF_END));
2147 /**********************************************************************
2148 * MENUEX_ParseResource
2150 * Parse an extended menu resource and add items to the menu.
2151 * Return a pointer to the end of the resource.
2153 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
2159 mii.cbSize = sizeof(mii);
2160 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
2161 mii.fType = GET_DWORD(res);
2162 res += sizeof(DWORD);
2163 mii.fState = GET_DWORD(res);
2164 res += sizeof(DWORD);
2165 mii.wID = GET_DWORD(res);
2166 res += sizeof(DWORD);
2167 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
2168 res += sizeof(WORD);
2169 /* Align the text on a word boundary. */
2170 res += (~((UINT_PTR)res - 1)) & 1;
2171 mii.dwTypeData = (LPWSTR) res;
2172 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2173 /* Align the following fields on a dword boundary. */
2174 res += (~((UINT_PTR)res - 1)) & 3;
2176 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2177 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
2179 if (resinfo & 1) { /* Pop-up? */
2180 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2181 res += sizeof(DWORD);
2182 mii.hSubMenu = CreatePopupMenu();
2185 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2186 DestroyMenu(mii.hSubMenu);
2189 mii.fMask |= MIIM_SUBMENU;
2190 mii.fType |= MF_POPUP;
2192 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
2194 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2195 mii.wID, mii.fType);
2196 mii.fType |= MF_SEPARATOR;
2198 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2199 } while (!(resinfo & MF_END));
2204 /***********************************************************************
2207 * Return the handle of the selected sub-popup menu (if any).
2209 static HMENU MENU_GetSubPopup( HMENU hmenu )
2214 menu = MENU_GetMenu( hmenu );
2216 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2218 item = &menu->items[menu->FocusedItem];
2219 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2220 return item->hSubMenu;
2225 /***********************************************************************
2226 * MENU_HideSubPopups
2228 * Hide the sub-popup menus of this menu.
2230 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2231 BOOL sendMenuSelect )
2233 POPUPMENU *menu = MENU_GetMenu( hmenu );
2235 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2237 if (menu && top_popup)
2243 if (menu->FocusedItem != NO_SELECTED_ITEM)
2245 item = &menu->items[menu->FocusedItem];
2246 if (!(item->fType & MF_POPUP) ||
2247 !(item->fState & MF_MOUSESELECT)) return;
2248 item->fState &= ~MF_MOUSESELECT;
2249 hsubmenu = item->hSubMenu;
2252 submenu = MENU_GetMenu( hsubmenu );
2253 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2254 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2255 DestroyWindow( submenu->hWnd );
2261 /***********************************************************************
2264 * Display the sub-menu of the selected item of this menu.
2265 * Return the handle of the submenu, or hmenu if no submenu to display.
2267 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2268 BOOL selectFirst, UINT wFlags )
2275 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, selectFirst);
2277 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2279 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
2281 item = &menu->items[menu->FocusedItem];
2282 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
2285 /* message must be sent before using item,
2286 because nearly everything may be changed by the application ! */
2288 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2289 if (!(wFlags & TPM_NONOTIFY))
2290 SendMessageW( hwndOwner, WM_INITMENUPOPUP, (WPARAM)item->hSubMenu,
2291 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2293 item = &menu->items[menu->FocusedItem];
2296 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2297 if (!(item->fState & MF_HILITE))
2299 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2300 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2302 SelectObject( hdc, get_menu_font(FALSE));
2304 item->fState |= MF_HILITE;
2305 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2306 ReleaseDC( menu->hWnd, hdc );
2308 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2311 item->fState |= MF_MOUSESELECT;
2313 if (IS_SYSTEM_MENU(menu))
2315 MENU_InitSysMenuPopup(item->hSubMenu,
2316 GetWindowLongW( menu->hWnd, GWL_STYLE ),
2317 GetClassLongW( menu->hWnd, GCL_STYLE));
2319 NC_GetSysPopupPos( menu->hWnd, &rect );
2320 rect.top = rect.bottom;
2321 rect.right = GetSystemMetrics(SM_CXSIZE);
2322 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2326 GetWindowRect( menu->hWnd, &rect );
2327 if (menu->wFlags & MF_POPUP)
2329 RECT rc = item->rect;
2331 MENU_AdjustMenuItemRect(menu, &rc);
2332 rect.left += rc.right - GetSystemMetrics(SM_CXBORDER);
2334 rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER);
2335 rect.bottom = rc.top - rc.bottom;
2339 rect.left += item->rect.left;
2340 rect.top += item->rect.bottom;
2341 rect.right = item->rect.right - item->rect.left;
2342 rect.bottom = item->rect.bottom - item->rect.top;
2346 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2347 rect.left, rect.top, rect.right, rect.bottom );
2349 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2350 return item->hSubMenu;
2355 /**********************************************************************
2358 HWND MENU_IsMenuActive(void)
2363 /***********************************************************************
2366 * Walks menu chain trying to find a menu pt maps to.
2368 static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2370 POPUPMENU *menu = MENU_GetMenu( hMenu );
2371 UINT item = menu->FocusedItem;
2374 /* try subpopup first (if any) */
2375 ret = (item != NO_SELECTED_ITEM &&
2376 (menu->items[item].fType & MF_POPUP) &&
2377 (menu->items[item].fState & MF_MOUSESELECT))
2378 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
2380 if (!ret) /* check the current window (avoiding WM_HITTEST) */
2382 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2383 if( menu->wFlags & MF_POPUP )
2385 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2387 else if (ht == HTSYSMENU)
2388 ret = get_win_sys_menu( menu->hWnd );
2389 else if (ht == HTMENU)
2390 ret = GetMenu( menu->hWnd );
2395 /***********************************************************************
2396 * MENU_ExecFocusedItem
2398 * Execute a menu item (for instance when user pressed Enter).
2399 * Return the wID of the executed item. Otherwise, -1 indicating
2400 * that no menu item was executed;
2401 * Have to receive the flags for the TrackPopupMenu options to avoid
2402 * sending unwanted message.
2405 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2408 POPUPMENU *menu = MENU_GetMenu( hMenu );
2410 TRACE("%p hmenu=%p\n", pmt, hMenu);
2412 if (!menu || !menu->nItems ||
2413 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2415 item = &menu->items[menu->FocusedItem];
2417 TRACE("%p %08x %p\n", hMenu, item->wID, item->hSubMenu);
2419 if (!(item->fType & MF_POPUP))
2421 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2423 /* If TPM_RETURNCMD is set you return the id, but
2424 do not send a message to the owner */
2425 if(!(wFlags & TPM_RETURNCMD))
2427 if( menu->wFlags & MF_SYSMENU )
2428 PostMessageW( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2429 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2431 PostMessageW( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2437 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2442 /***********************************************************************
2443 * MENU_SwitchTracking
2445 * Helper function for menu navigation routines.
2447 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2449 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2450 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2452 TRACE("%p hmenu=%p 0x%04x\n", pmt, hPtMenu, id);
2454 if( pmt->hTopMenu != hPtMenu &&
2455 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2457 /* both are top level menus (system and menu-bar) */
2458 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2459 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2460 pmt->hTopMenu = hPtMenu;
2462 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2463 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2467 /***********************************************************************
2470 * Return TRUE if we can go on with menu tracking.
2472 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2474 TRACE("%p hPtMenu=%p\n", pmt, hPtMenu);
2479 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2482 if( IS_SYSTEM_MENU(ptmenu) )
2483 item = ptmenu->items;
2485 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2489 if( ptmenu->FocusedItem != id )
2490 MENU_SwitchTracking( pmt, hPtMenu, id );
2492 /* If the popup menu is not already "popped" */
2493 if(!(item->fState & MF_MOUSESELECT ))
2495 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2500 /* Else the click was on the menu bar, finish the tracking */
2505 /***********************************************************************
2508 * Return the value of MENU_ExecFocusedItem if
2509 * the selected item was not a popup. Else open the popup.
2510 * A -1 return value indicates that we go on with menu tracking.
2513 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2515 TRACE("%p hmenu=%p\n", pmt, hPtMenu);
2520 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2523 if( IS_SYSTEM_MENU(ptmenu) )
2524 item = ptmenu->items;
2526 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2528 if( item && (ptmenu->FocusedItem == id ))
2530 if( !(item->fType & MF_POPUP) )
2531 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2533 /* If we are dealing with the top-level menu */
2534 /* and this is a click on an already "popped" item: */
2535 /* Stop the menu tracking and close the opened submenus */
2536 if((pmt->hTopMenu == hPtMenu) && ptmenu->bTimeToHide)
2539 ptmenu->bTimeToHide = TRUE;
2545 /***********************************************************************
2548 * Return TRUE if we can go on with menu tracking.
2550 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2552 UINT id = NO_SELECTED_ITEM;
2553 POPUPMENU *ptmenu = NULL;
2557 ptmenu = MENU_GetMenu( hPtMenu );
2558 if( IS_SYSTEM_MENU(ptmenu) )
2561 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2564 if( id == NO_SELECTED_ITEM )
2566 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2567 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2570 else if( ptmenu->FocusedItem != id )
2572 MENU_SwitchTracking( pmt, hPtMenu, id );
2573 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2579 /***********************************************************************
2582 static void MENU_SetCapture( HWND hwnd )
2586 SERVER_START_REQ( set_capture_window )
2589 req->flags = CAPTURE_MENU;
2590 if (!wine_server_call_err( req ))
2592 previous = reply->previous;
2593 hwnd = reply->full_handle;
2598 if (previous && previous != hwnd)
2599 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
2603 /***********************************************************************
2606 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2608 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2610 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2612 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2613 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2615 MDINEXTMENU next_menu;
2620 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2621 next_menu.hmenuNext = 0;
2622 next_menu.hwndNext = 0;
2623 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2625 TRACE("%p [%p] -> %p [%p]\n",
2626 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2628 if (!next_menu.hmenuNext || !next_menu.hwndNext)
2630 DWORD style = GetWindowLongW( pmt->hOwnerWnd, GWL_STYLE );
2631 hNewWnd = pmt->hOwnerWnd;
2632 if( IS_SYSTEM_MENU(menu) )
2634 /* switch to the menu bar */
2636 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2640 menu = MENU_GetMenu( hNewMenu );
2641 id = menu->nItems - 1;
2644 else if (style & WS_SYSMENU )
2646 /* switch to the system menu */
2647 hNewMenu = get_win_sys_menu( hNewWnd );
2651 else /* application returned a new menu to switch to */
2653 hNewMenu = next_menu.hmenuNext;
2654 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2656 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2658 DWORD style = GetWindowLongW( hNewWnd, GWL_STYLE );
2660 if (style & WS_SYSMENU &&
2661 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2663 /* get the real system menu */
2664 hNewMenu = get_win_sys_menu(hNewWnd);
2666 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2668 /* FIXME: Not sure what to do here;
2669 * perhaps try to track hNewMenu as a popup? */
2671 TRACE(" -- got confused.\n");
2678 if( hNewMenu != pmt->hTopMenu )
2680 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2682 if( pmt->hCurrentMenu != pmt->hTopMenu )
2683 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2686 if( hNewWnd != pmt->hOwnerWnd )
2688 pmt->hOwnerWnd = hNewWnd;
2689 MENU_SetCapture( pmt->hOwnerWnd );
2692 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2693 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2700 /***********************************************************************
2703 * The idea is not to show the popup if the next input message is
2704 * going to hide it anyway.
2706 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2710 msg.hwnd = pmt->hOwnerWnd;
2712 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2713 pmt->trackFlags |= TF_SKIPREMOVE;
2718 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2719 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2721 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2722 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2723 if( msg.message == WM_KEYDOWN &&
2724 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2726 pmt->trackFlags |= TF_SUSPENDPOPUP;
2733 /* failures go through this */
2734 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2738 /***********************************************************************
2741 * Handle a VK_ESCAPE key event in a menu.
2743 static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2745 BOOL bEndMenu = TRUE;
2747 if (pmt->hCurrentMenu != pmt->hTopMenu)
2749 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2751 if (menu->wFlags & MF_POPUP)
2753 HMENU hmenutmp, hmenuprev;
2755 hmenuprev = hmenutmp = pmt->hTopMenu;
2757 /* close topmost popup */
2758 while (hmenutmp != pmt->hCurrentMenu)
2760 hmenuprev = hmenutmp;
2761 hmenutmp = MENU_GetSubPopup( hmenuprev );
2764 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2765 pmt->hCurrentMenu = hmenuprev;
2773 /***********************************************************************
2776 * Handle a VK_LEFT key event in a menu.
2778 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2781 HMENU hmenutmp, hmenuprev;
2784 hmenuprev = hmenutmp = pmt->hTopMenu;
2785 menu = MENU_GetMenu( hmenutmp );
2787 /* Try to move 1 column left (if possible) */
2788 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2789 NO_SELECTED_ITEM ) {
2791 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2796 /* close topmost popup */
2797 while (hmenutmp != pmt->hCurrentMenu)
2799 hmenuprev = hmenutmp;
2800 hmenutmp = MENU_GetSubPopup( hmenuprev );
2803 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2804 pmt->hCurrentMenu = hmenuprev;
2806 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2808 /* move menu bar selection if no more popups are left */
2810 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2811 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2813 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2815 /* A sublevel menu was displayed - display the next one
2816 * unless there is another displacement coming up */
2818 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2819 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2820 pmt->hTopMenu, TRUE, wFlags);
2826 /***********************************************************************
2829 * Handle a VK_RIGHT key event in a menu.
2831 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2834 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2837 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2839 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->items[0].text),
2840 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2842 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2844 /* If already displaying a popup, try to display sub-popup */
2846 hmenutmp = pmt->hCurrentMenu;
2847 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2849 /* if subpopup was displayed then we are done */
2850 if (hmenutmp != pmt->hCurrentMenu) return;
2853 /* Check to see if there's another column */
2854 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2855 NO_SELECTED_ITEM ) {
2856 TRACE("Going to %d.\n", nextcol );
2857 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2862 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2864 if( pmt->hCurrentMenu != pmt->hTopMenu )
2866 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2867 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2868 } else hmenutmp = 0;
2870 /* try to move to the next item */
2871 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2872 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2874 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2875 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2876 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2877 pmt->hTopMenu, TRUE, wFlags);
2881 /***********************************************************************
2884 * Menu tracking code.
2886 static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2887 HWND hwnd, const RECT *lprect )
2892 INT executedMenuId = -1;
2894 BOOL enterIdleSent = FALSE;
2897 mt.hCurrentMenu = hmenu;
2898 mt.hTopMenu = hmenu;
2899 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2903 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p %s\n",
2904 hmenu, wFlags, x, y, hwnd, wine_dbgstr_rect( lprect));
2907 if (!(menu = MENU_GetMenu( hmenu )))
2909 WARN("Invalid menu handle %p\n", hmenu);
2910 SetLastError(ERROR_INVALID_MENU_HANDLE);
2914 if (wFlags & TPM_BUTTONDOWN)
2916 /* Get the result in order to start the tracking or not */
2917 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2918 fEndMenu = !fRemove;
2921 if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
2923 MENU_SetCapture( mt.hOwnerWnd );
2927 menu = MENU_GetMenu( mt.hCurrentMenu );
2928 if (!menu) /* sometimes happens if I do a window manager close */
2931 /* we have to keep the message in the queue until it's
2932 * clear that menu loop is not over yet. */
2936 if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
2938 if (!CallMsgFilterW( &msg, MSGF_MENU )) break;
2939 /* remove the message from the queue */
2940 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2946 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2947 enterIdleSent = TRUE;
2948 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2954 /* check if EndMenu() tried to cancel us, by posting this message */
2955 if(msg.message == WM_CANCELMODE)
2957 /* we are now out of the loop */
2960 /* remove the message from the queue */
2961 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2963 /* break out of internal loop, ala ESCAPE */
2967 TranslateMessage( &msg );
2970 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2971 enterIdleSent=FALSE;
2974 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2977 * Use the mouse coordinates in lParam instead of those in the MSG
2978 * struct to properly handle synthetic messages. They are already
2979 * in screen coordinates.
2981 mt.pt.x = (short)LOWORD(msg.lParam);
2982 mt.pt.y = (short)HIWORD(msg.lParam);
2984 /* Find a menu for this mouse event */
2985 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2989 /* no WM_NC... messages in captured state */
2991 case WM_RBUTTONDBLCLK:
2992 case WM_RBUTTONDOWN:
2993 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2995 case WM_LBUTTONDBLCLK:
2996 case WM_LBUTTONDOWN:
2997 /* If the message belongs to the menu, removes it from the queue */
2998 /* Else, end menu tracking */
2999 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
3000 fEndMenu = !fRemove;
3004 if (!(wFlags & TPM_RIGHTBUTTON)) break;
3007 /* Check if a menu was selected by the mouse */
3010 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
3012 /* End the loop if executedMenuId is an item ID */
3013 /* or if the job was done (executedMenuId = 0). */
3014 fEndMenu = fRemove = (executedMenuId != -1);
3016 /* No menu was selected by the mouse */
3017 /* if the function was called by TrackPopupMenu, continue
3018 with the menu tracking. If not, stop it */
3020 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
3025 /* the selected menu item must be changed every time */
3026 /* the mouse moves. */
3029 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
3031 } /* switch(msg.message) - mouse */
3033 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
3035 fRemove = TRUE; /* Keyboard messages are always removed */
3048 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
3049 NO_SELECTED_ITEM, FALSE, 0 );
3052 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
3053 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
3056 case VK_DOWN: /* If on menu bar, pull-down the menu */
3058 menu = MENU_GetMenu( mt.hCurrentMenu );
3059 if (!(menu->wFlags & MF_POPUP))
3060 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
3061 else /* otherwise try to move selection */
3062 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
3066 MENU_KeyLeft( &mt, wFlags );
3070 MENU_KeyRight( &mt, wFlags );
3074 fEndMenu = MENU_KeyEscape(&mt, wFlags);
3080 hi.cbSize = sizeof(HELPINFO);
3081 hi.iContextType = HELPINFO_MENUITEM;
3082 if (menu->FocusedItem == NO_SELECTED_ITEM)
3085 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
3086 hi.hItemHandle = hmenu;
3087 hi.dwContextId = menu->dwContextHelpID;
3088 hi.MousePos = msg.pt;
3089 SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
3096 break; /* WM_KEYDOWN */
3103 if (msg.wParam == '\r' || msg.wParam == ' ')
3105 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3106 fEndMenu = (executedMenuId != -1);
3111 /* Hack to avoid control chars. */
3112 /* We will find a better way real soon... */
3113 if (msg.wParam < 32) break;
3115 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
3116 LOWORD(msg.wParam), FALSE );
3117 if (pos == (UINT)-2) fEndMenu = TRUE;
3118 else if (pos == (UINT)-1) MessageBeep(0);
3121 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
3123 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3124 fEndMenu = (executedMenuId != -1);
3128 } /* switch(msg.message) - kbd */
3132 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
3133 DispatchMessageW( &msg );
3137 if (!fEndMenu) fRemove = TRUE;
3139 /* finally remove message from the queue */
3141 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
3142 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
3143 else mt.trackFlags &= ~TF_SKIPREMOVE;
3146 MENU_SetCapture(0); /* release the capture */
3148 /* If dropdown is still painted and the close box is clicked on
3149 then the menu will be destroyed as part of the DispatchMessage above.
3150 This will then invalidate the menu handle in mt.hTopMenu. We should
3151 check for this first. */
3152 if( IsMenu( mt.hTopMenu ) )
3154 menu = MENU_GetMenu( mt.hTopMenu );
3156 if( IsWindow( mt.hOwnerWnd ) )
3158 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
3160 if (menu && (menu->wFlags & MF_POPUP))
3162 DestroyWindow( menu->hWnd );
3165 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3166 SendMessageW( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
3169 /* Reset the variable for hiding menu */
3170 if( menu ) menu->bTimeToHide = FALSE;
3173 /* The return value is only used by TrackPopupMenu */
3174 if (!(wFlags & TPM_RETURNCMD)) return TRUE;
3175 if (executedMenuId == -1) executedMenuId = 0;
3176 return executedMenuId;
3179 /***********************************************************************
3182 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
3186 TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
3190 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3191 if (!(wFlags & TPM_NONOTIFY))
3192 SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
3194 SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
3196 if (!(wFlags & TPM_NONOTIFY))
3198 SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
3199 /* If an app changed/recreated menu bar entries in WM_INITMENU
3200 * menu sizes will be recalculated once the menu created/shown.
3204 /* This makes the menus of applications built with Delphi work.
3205 * It also enables menus to be displayed in more than one window,
3206 * but there are some bugs left that need to be fixed in this case.
3208 if ((menu = MENU_GetMenu( hMenu ))) menu->hWnd = hWnd;
3212 /***********************************************************************
3215 static BOOL MENU_ExitTracking(HWND hWnd)
3217 TRACE("hwnd=%p\n", hWnd);
3219 SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 );
3225 /***********************************************************************
3226 * MENU_TrackMouseMenuBar
3228 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3230 void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
3232 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
3233 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3235 TRACE("wnd=%p ht=0x%04x %s\n", hWnd, ht, wine_dbgstr_point( &pt));
3239 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
3240 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
3241 MENU_ExitTracking(hWnd);
3246 /***********************************************************************
3247 * MENU_TrackKbdMenuBar
3249 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3251 void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar)
3253 UINT uItem = NO_SELECTED_ITEM;
3255 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3257 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
3259 /* find window that has a menu */
3261 while (!WIN_ALLOWED_MENU(GetWindowLongW( hwnd, GWL_STYLE )))
3262 if (!(hwnd = GetAncestor( hwnd, GA_PARENT ))) return;
3264 /* check if we have to track a system menu */
3266 hTrackMenu = GetMenu( hwnd );
3267 if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' )
3269 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
3270 hTrackMenu = get_win_sys_menu( hwnd );
3272 wParam |= HTSYSMENU; /* prevent item lookup */
3275 if (!IsMenu( hTrackMenu )) return;
3277 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3279 if( wChar && wChar != ' ' )
3281 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) );
3282 if ( uItem >= (UINT)(-2) )
3284 if( uItem == (UINT)(-1) ) MessageBeep(0);
3285 /* schedule end of menu tracking */
3286 wFlags |= TF_ENDMENU;
3291 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3293 if (wParam & HTSYSMENU)
3295 /* prevent sysmenu activation for managed windows on Alt down/up */
3296 if (GetPropA( hwnd, "__wine_x11_managed" ))
3297 wFlags |= TF_ENDMENU; /* schedule end of menu tracking */
3301 if( uItem == NO_SELECTED_ITEM )
3302 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3304 PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3308 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3309 MENU_ExitTracking( hwnd );
3313 /**********************************************************************
3314 * TrackPopupMenu (USER32.@)
3316 * Like the win32 API, the function return the command ID only if the
3317 * flag TPM_RETURNCMD is on.
3320 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3321 INT nReserved, HWND hWnd, const RECT *lpRect )
3325 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3327 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3328 if (!(wFlags & TPM_NONOTIFY))
3329 SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0);
3331 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3332 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3333 MENU_ExitTracking(hWnd);
3338 /**********************************************************************
3339 * TrackPopupMenuEx (USER32.@)
3341 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3342 HWND hWnd, LPTPMPARAMS lpTpm )
3344 FIXME("not fully implemented\n" );
3345 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3346 lpTpm ? &lpTpm->rcExclude : NULL );
3349 /***********************************************************************
3352 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3354 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3356 TRACE("hwnd=%p msg=0x%04x wp=0x%04x lp=0x%08lx\n", hwnd, message, wParam, lParam);
3362 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3363 SetWindowLongPtrW( hwnd, 0, (LONG_PTR)cs->lpCreateParams );
3367 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3368 return MA_NOACTIVATE;
3373 BeginPaint( hwnd, &ps );
3374 MENU_DrawPopupMenu( hwnd, ps.hdc,
3375 (HMENU)GetWindowLongPtrW( hwnd, 0 ) );
3376 EndPaint( hwnd, &ps );
3383 /* zero out global pointer in case resident popup window was destroyed. */
3384 if (hwnd == top_popup) top_popup = 0;
3391 if (!GetWindowLongPtrW( hwnd, 0 )) ERR("no menu to display\n");
3394 SetWindowLongPtrW( hwnd, 0, 0 );
3397 case MM_SETMENUHANDLE:
3398 SetWindowLongPtrW( hwnd, 0, wParam );
3401 case MM_GETMENUHANDLE:
3402 return GetWindowLongPtrW( hwnd, 0 );
3405 return DefWindowProcW( hwnd, message, wParam, lParam );
3411 /***********************************************************************
3412 * MENU_GetMenuBarHeight
3414 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3416 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3417 INT orgX, INT orgY )
3423 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
3425 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3427 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3428 SelectObject( hdc, get_menu_font(FALSE));
3429 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3430 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3431 ReleaseDC( hwnd, hdc );
3432 return lppop->Height;
3436 /*******************************************************************
3437 * ChangeMenuA (USER32.@)
3439 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3440 UINT id, UINT flags )
3442 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3443 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3445 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3446 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3448 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3449 flags & MF_BYPOSITION ? pos : id,
3450 flags & ~MF_REMOVE );
3451 /* Default: MF_INSERT */
3452 return InsertMenuA( hMenu, pos, flags, id, data );
3456 /*******************************************************************
3457 * ChangeMenuW (USER32.@)
3459 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3460 UINT id, UINT flags )
3462 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3463 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3465 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3466 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3468 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3469 flags & MF_BYPOSITION ? pos : id,
3470 flags & ~MF_REMOVE );
3471 /* Default: MF_INSERT */
3472 return InsertMenuW( hMenu, pos, flags, id, data );
3476 /*******************************************************************
3477 * CheckMenuItem (USER32.@)
3479 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3484 TRACE("menu=%p id=%04x flags=%04x\n", hMenu, id, flags );
3485 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3486 ret = item->fState & MF_CHECKED;
3487 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3488 else item->fState &= ~MF_CHECKED;
3493 /**********************************************************************
3494 * EnableMenuItem (USER32.@)
3496 BOOL WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3502 TRACE("(%p, %04x, %04x) !\n", hMenu, wItemID, wFlags);
3504 /* Get the Popupmenu to access the owner menu */
3505 if (!(menu = MENU_GetMenu(hMenu)))
3508 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3511 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3512 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3514 /* If the close item in the system menu change update the close button */
3515 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3517 if (menu->hSysMenuOwner != 0)
3520 POPUPMENU* parentMenu;
3522 /* Get the parent menu to access*/
3523 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3526 /* Refresh the frame to reflect the change */
3527 GetWindowRect(parentMenu->hWnd, &rc);
3528 MapWindowPoints(0, parentMenu->hWnd, (POINT *)&rc, 2);
3530 RedrawWindow(parentMenu->hWnd, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
3538 /*******************************************************************
3539 * GetMenuStringA (USER32.@)
3541 INT WINAPI GetMenuStringA(
3542 HMENU hMenu, /* [in] menuhandle */
3543 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3544 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3545 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3546 UINT wFlags /* [in] MF_ flags */
3550 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3551 if (str && nMaxSiz) str[0] = '\0';
3552 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
3553 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
3556 if (!item->text) return 0;
3557 if (!str || !nMaxSiz) return strlenW(item->text);
3558 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3560 TRACE("returning '%s'\n", str );
3565 /*******************************************************************
3566 * GetMenuStringW (USER32.@)
3568 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3569 LPWSTR str, INT nMaxSiz, UINT wFlags )
3573 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3574 if (str && nMaxSiz) str[0] = '\0';
3575 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
3576 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
3579 if (!str || !nMaxSiz) return item->text ? strlenW(item->text) : 0;
3580 if( !(item->text)) {
3584 lstrcpynW( str, item->text, nMaxSiz );
3585 return strlenW(str);
3589 /**********************************************************************
3590 * HiliteMenuItem (USER32.@)
3592 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3596 TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
3597 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3598 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3599 if (menu->FocusedItem == wItemID) return TRUE;
3600 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3601 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3606 /**********************************************************************
3607 * GetMenuState (USER32.@)
3609 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3612 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, wItemID, wFlags);
3613 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3614 debug_print_menuitem (" item: ", item, "");
3615 if (item->fType & MF_POPUP)
3617 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3618 if (!menu) return -1;
3619 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3623 /* We used to (from way back then) mask the result to 0xff. */
3624 /* I don't know why and it seems wrong as the documented */
3625 /* return flag MF_SEPARATOR is outside that mask. */
3626 return (item->fType | item->fState);
3631 /**********************************************************************
3632 * GetMenuItemCount (USER32.@)
3634 INT WINAPI GetMenuItemCount( HMENU hMenu )
3636 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3637 if (!menu) return -1;
3638 TRACE("(%p) returning %d\n", hMenu, menu->nItems );
3639 return menu->nItems;
3643 /**********************************************************************
3644 * GetMenuItemID (USER32.@)
3646 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3650 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
3651 if (lpmi->fType & MF_POPUP) return -1;
3657 /*******************************************************************
3658 * InsertMenuW (USER32.@)
3660 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3661 UINT_PTR id, LPCWSTR str )
3665 if (IS_STRING_ITEM(flags) && str)
3666 TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3667 hMenu, pos, flags, id, debugstr_w(str) );
3668 else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %p (not a string)\n",
3669 hMenu, pos, flags, id, str );
3671 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3673 if (!(MENU_SetItemData( item, flags, id, str )))
3675 RemoveMenu( hMenu, pos, flags );
3679 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3680 (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
3682 item->hCheckBit = item->hUnCheckBit = 0;
3687 /*******************************************************************
3688 * InsertMenuA (USER32.@)
3690 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3691 UINT_PTR id, LPCSTR str )
3695 if (IS_STRING_ITEM(flags) && str)
3697 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3698 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3701 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3702 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3703 HeapFree( GetProcessHeap(), 0, newstr );
3707 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3711 /*******************************************************************
3712 * AppendMenuA (USER32.@)
3714 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3715 UINT_PTR id, LPCSTR data )
3717 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3721 /*******************************************************************
3722 * AppendMenuW (USER32.@)
3724 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3725 UINT_PTR id, LPCWSTR data )
3727 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3731 /**********************************************************************
3732 * RemoveMenu (USER32.@)
3734 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3739 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3740 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3741 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3745 MENU_FreeItemData( item );
3747 if (--menu->nItems == 0)
3749 HeapFree( GetProcessHeap(), 0, menu->items );
3754 while(nPos < menu->nItems)
3760 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3761 menu->nItems * sizeof(MENUITEM) );
3767 /**********************************************************************
3768 * DeleteMenu (USER32.@)
3770 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3772 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3773 if (!item) return FALSE;
3774 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3775 /* nPos is now the position of the item */
3776 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3781 /*******************************************************************
3782 * ModifyMenuW (USER32.@)
3784 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3785 UINT_PTR id, LPCWSTR str )
3789 if (IS_STRING_ITEM(flags))
3790 TRACE("%p %d %04x %04x %s\n", hMenu, pos, flags, id, debugstr_w(str) );
3792 TRACE("%p %d %04x %04x %p\n", hMenu, pos, flags, id, str );
3794 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3795 MENU_GetMenu(hMenu)->Height = 0; /* force size recalculate */
3796 return MENU_SetItemData( item, flags, id, str );
3800 /*******************************************************************
3801 * ModifyMenuA (USER32.@)
3803 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3804 UINT_PTR id, LPCSTR str )
3808 if (IS_STRING_ITEM(flags) && str)
3810 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3811 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3814 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3815 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3816 HeapFree( GetProcessHeap(), 0, newstr );
3820 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3824 /**********************************************************************
3825 * CreatePopupMenu (USER32.@)
3827 HMENU WINAPI CreatePopupMenu(void)
3832 if (!(hmenu = CreateMenu())) return 0;
3833 menu = MENU_GetMenu( hmenu );
3834 menu->wFlags |= MF_POPUP;
3835 menu->bTimeToHide = FALSE;
3840 /**********************************************************************
3841 * GetMenuCheckMarkDimensions (USER.417)
3842 * GetMenuCheckMarkDimensions (USER32.@)
3844 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3846 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3850 /**********************************************************************
3851 * SetMenuItemBitmaps (USER32.@)
3853 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3854 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3857 TRACE("(%p, %04x, %04x, %p, %p)\n",
3858 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3859 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3861 if (!hNewCheck && !hNewUnCheck)
3863 item->fState &= ~MF_USECHECKBITMAPS;
3865 else /* Install new bitmaps */
3867 item->hCheckBit = hNewCheck;
3868 item->hUnCheckBit = hNewUnCheck;
3869 item->fState |= MF_USECHECKBITMAPS;
3875 /**********************************************************************
3876 * CreateMenu (USER32.@)
3878 HMENU WINAPI CreateMenu(void)
3882 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3883 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3885 ZeroMemory(menu, sizeof(POPUPMENU));
3886 menu->wMagic = MENU_MAGIC;
3887 menu->FocusedItem = NO_SELECTED_ITEM;
3888 menu->bTimeToHide = FALSE;
3890 TRACE("return %p\n", hMenu );
3896 /**********************************************************************
3897 * DestroyMenu (USER32.@)
3899 BOOL WINAPI DestroyMenu( HMENU hMenu )
3901 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3903 TRACE("(%p)\n", hMenu);
3906 if (!lppop) return FALSE;
3908 lppop->wMagic = 0; /* Mark it as destroyed */
3910 /* DestroyMenu should not destroy system menu popup owner */
3911 if ((lppop->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && lppop->hWnd)
3913 DestroyWindow( lppop->hWnd );
3917 if (lppop->items) /* recursively destroy submenus */
3920 MENUITEM *item = lppop->items;
3921 for (i = lppop->nItems; i > 0; i--, item++)
3923 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3924 MENU_FreeItemData( item );
3926 HeapFree( GetProcessHeap(), 0, lppop->items );
3928 USER_HEAP_FREE( hMenu );
3933 /**********************************************************************
3934 * GetSystemMenu (USER32.@)
3936 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3938 WND *wndPtr = WIN_GetPtr( hWnd );
3941 if (wndPtr == WND_DESKTOP) return 0;
3942 if (wndPtr == WND_OTHER_PROCESS)
3944 if (IsWindow( hWnd )) FIXME( "not supported on other process window %p\n", hWnd );
3948 if (wndPtr->hSysMenu && bRevert)
3950 DestroyMenu(wndPtr->hSysMenu);
3951 wndPtr->hSysMenu = 0;
3954 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3955 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, 0 );
3957 if( wndPtr->hSysMenu )
3960 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3962 /* Store the dummy sysmenu handle to facilitate the refresh */
3963 /* of the close button if the SC_CLOSE item change */
3964 menu = MENU_GetMenu(retvalue);
3966 menu->hSysMenuOwner = wndPtr->hSysMenu;
3968 WIN_ReleasePtr( wndPtr );
3970 return bRevert ? 0 : retvalue;
3974 /*******************************************************************
3975 * SetSystemMenu (USER32.@)
3977 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3979 WND *wndPtr = WIN_GetPtr( hwnd );
3981 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
3983 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3984 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3985 WIN_ReleasePtr( wndPtr );
3992 /**********************************************************************
3993 * GetMenu (USER32.@)
3995 HMENU WINAPI GetMenu( HWND hWnd )
3997 HMENU retvalue = (HMENU)GetWindowLongPtrW( hWnd, GWLP_ID );
3998 TRACE("for %p returning %p\n", hWnd, retvalue);
4002 /**********************************************************************
4003 * GetMenuBarInfo (USER32.@)
4005 BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi )
4007 FIXME( "(%p,0x%08lx,0x%08lx,%p)\n", hwnd, idObject, idItem, pmbi );
4011 /**********************************************************************
4014 * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
4015 * SetWindowPos call that would result if SetMenu were called directly.
4017 BOOL MENU_SetMenu( HWND hWnd, HMENU hMenu )
4019 TRACE("(%p, %p);\n", hWnd, hMenu);
4021 if (hMenu && !IsMenu(hMenu))
4023 WARN("hMenu %p is not a menu handle\n", hMenu);
4024 SetLastError(ERROR_INVALID_MENU_HANDLE);
4027 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
4030 hWnd = WIN_GetFullHandle( hWnd );
4031 if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */
4037 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
4039 lpmenu->hWnd = hWnd;
4040 lpmenu->Height = 0; /* Make sure we recalculate the size */
4042 SetWindowLongPtrW( hWnd, GWLP_ID, (LONG_PTR)hMenu );
4047 /**********************************************************************
4048 * SetMenu (USER32.@)
4050 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4052 if(!MENU_SetMenu(hWnd, hMenu))
4055 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4056 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4061 /**********************************************************************
4062 * GetSubMenu (USER32.@)
4064 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4068 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return 0;
4069 if (!(lpmi->fType & MF_POPUP)) return 0;
4070 return lpmi->hSubMenu;
4074 /**********************************************************************
4075 * DrawMenuBar (USER32.@)
4077 BOOL WINAPI DrawMenuBar( HWND hWnd )
4080 HMENU hMenu = GetMenu(hWnd);
4082 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
4084 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4086 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4087 lppop->hwndOwner = hWnd;
4088 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4089 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4093 /***********************************************************************
4094 * DrawMenuBarTemp (USER32.@)
4098 * called by W98SE desk.cpl Control Panel Applet
4100 * Not 100% sure about the param names, but close.
4102 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont)
4107 BOOL flat_menu = FALSE;
4109 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
4112 hMenu = GetMenu(hwnd);
4115 hFont = get_menu_font(FALSE);
4117 lppop = MENU_GetMenu( hMenu );
4118 if (lppop == NULL || lprect == NULL)
4120 retvalue = GetSystemMetrics(SM_CYMENU);
4124 TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont);
4126 hfontOld = SelectObject( hDC, hFont);
4128 if (lppop->Height == 0)
4129 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
4131 lprect->bottom = lprect->top + lppop->Height;
4133 FillRect(hDC, lprect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU) );
4135 SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE));
4136 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
4137 LineTo( hDC, lprect->right, lprect->bottom );
4139 if (lppop->nItems == 0)
4141 retvalue = GetSystemMetrics(SM_CYMENU);
4145 for (i = 0; i < lppop->nItems; i++)
4147 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
4148 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
4150 retvalue = lppop->Height;
4153 if (hfontOld) SelectObject (hDC, hfontOld);
4157 /***********************************************************************
4158 * EndMenu (USER.187)
4159 * EndMenu (USER32.@)
4161 void WINAPI EndMenu(void)
4163 /* if we are in the menu code, and it is active */
4164 if (!fEndMenu && top_popup)
4166 /* terminate the menu handling code */
4169 /* needs to be posted to wakeup the internal menu handler */
4170 /* which will now terminate the menu, in the event that */
4171 /* the main window was minimized, or lost focus, so we */
4172 /* don't end up with an orphaned menu */
4173 PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
4178 /***********************************************************************
4179 * LookupMenuHandle (USER.217)
4181 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4183 HMENU hmenu32 = HMENU_32(hmenu);
4185 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4186 else return HMENU_16(hmenu32);
4190 /**********************************************************************
4191 * LoadMenu (USER.150)
4193 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4199 if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4200 if (!name) return 0;
4202 instance = GetExePtr( instance );
4203 if (!(hRsrc = FindResource16( instance, name, (LPSTR)RT_MENU ))) return 0;
4204 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4205 hMenu = LoadMenuIndirect16(LockResource16(handle));
4206 FreeResource16( handle );
4211 /*****************************************************************
4212 * LoadMenuA (USER32.@)
4214 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4216 HRSRC hrsrc = FindResourceA( instance, name, (LPSTR)RT_MENU );
4217 if (!hrsrc) return 0;
4218 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4222 /*****************************************************************
4223 * LoadMenuW (USER32.@)
4225 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4227 HRSRC hrsrc = FindResourceW( instance, name, (LPWSTR)RT_MENU );
4228 if (!hrsrc) return 0;
4229 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4233 /**********************************************************************
4234 * LoadMenuIndirect (USER.220)
4236 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4239 WORD version, offset;
4240 LPCSTR p = (LPCSTR)template;
4242 TRACE("(%p)\n", template );
4243 version = GET_WORD(p);
4247 WARN("version must be 0 for Win16\n" );
4250 offset = GET_WORD(p);
4251 p += sizeof(WORD) + offset;
4252 if (!(hMenu = CreateMenu())) return 0;
4253 if (!MENU_ParseResource( p, hMenu, FALSE ))
4255 DestroyMenu( hMenu );
4258 return HMENU_16(hMenu);
4262 /**********************************************************************
4263 * LoadMenuIndirectW (USER32.@)
4265 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4268 WORD version, offset;
4269 LPCSTR p = (LPCSTR)template;
4271 version = GET_WORD(p);
4273 TRACE("%p, ver %d\n", template, version );
4276 case 0: /* standard format is version of 0 */
4277 offset = GET_WORD(p);
4278 p += sizeof(WORD) + offset;
4279 if (!(hMenu = CreateMenu())) return 0;
4280 if (!MENU_ParseResource( p, hMenu, TRUE ))
4282 DestroyMenu( hMenu );
4286 case 1: /* extended format is version of 1 */
4287 offset = GET_WORD(p);
4288 p += sizeof(WORD) + offset;
4289 if (!(hMenu = CreateMenu())) return 0;
4290 if (!MENUEX_ParseResource( p, hMenu))
4292 DestroyMenu( hMenu );
4297 ERR("version %d not supported.\n", version);
4303 /**********************************************************************
4304 * LoadMenuIndirectA (USER32.@)
4306 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4308 return LoadMenuIndirectW( template );
4312 /**********************************************************************
4315 BOOL WINAPI IsMenu(HMENU hmenu)
4317 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4318 return menu != NULL;
4321 /**********************************************************************
4322 * GetMenuItemInfo_common
4325 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4326 LPMENUITEMINFOW lpmii, BOOL unicode)
4328 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4330 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4335 if( lpmii->fMask & MIIM_TYPE) {
4336 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4337 WARN("invalid combination of fMask bits used\n");
4338 /* this does not happen on Win9x/ME */
4339 SetLastError( ERROR_INVALID_PARAMETER);
4342 lpmii->fType = menu->fType & ~MF_POPUP;
4343 if( menu->hbmpItem) lpmii->fType |= MFT_BITMAP;
4344 lpmii->hbmpItem = menu->hbmpItem; /* not on Win9x/ME */
4345 if( lpmii->fType & MFT_BITMAP) {
4346 lpmii->dwTypeData = (LPWSTR) menu->hbmpItem;
4348 } else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR)) {
4349 /* this does not happen on Win9x/ME */
4350 lpmii->dwTypeData = 0;
4355 /* copy the text string */
4356 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING))) {
4358 if(lpmii->dwTypeData && lpmii->cch) {
4361 *((WCHAR *)lpmii->dwTypeData) = 0;
4363 *((CHAR *)lpmii->dwTypeData) = 0;
4369 len = strlenW(menu->text);
4370 if(lpmii->dwTypeData && lpmii->cch)
4371 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4375 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL,
4376 0, NULL, NULL ) - 1;
4377 if(lpmii->dwTypeData && lpmii->cch)
4378 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4379 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4380 ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
4382 /* if we've copied a substring we return its length */
4383 if(lpmii->dwTypeData && lpmii->cch)
4384 if (lpmii->cch <= len + 1)
4389 /* return length of string */
4390 /* not on Win9x/ME if fType & MFT_BITMAP */
4396 if (lpmii->fMask & MIIM_FTYPE)
4397 lpmii->fType = menu->fType & ~MF_POPUP;
4399 if (lpmii->fMask & MIIM_BITMAP)
4400 lpmii->hbmpItem = menu->hbmpItem;
4402 if (lpmii->fMask & MIIM_STATE)
4403 lpmii->fState = menu->fState;
4405 if (lpmii->fMask & MIIM_ID)
4406 lpmii->wID = menu->wID;
4408 if (lpmii->fMask & MIIM_SUBMENU)
4409 lpmii->hSubMenu = menu->hSubMenu;
4411 /* hSubMenu is always cleared
4412 * (not on Win9x/ME ) */
4413 lpmii->hSubMenu = 0;
4416 if (lpmii->fMask & MIIM_CHECKMARKS) {
4417 lpmii->hbmpChecked = menu->hCheckBit;
4418 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4420 if (lpmii->fMask & MIIM_DATA)
4421 lpmii->dwItemData = menu->dwItemData;
4426 /**********************************************************************
4427 * GetMenuItemInfoA (USER32.@)
4429 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4430 LPMENUITEMINFOA lpmii)
4434 if( lpmii->cbSize != sizeof( mii) &&
4435 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4436 SetLastError( ERROR_INVALID_PARAMETER);
4439 memcpy( &mii, lpmii, lpmii->cbSize);
4440 mii.cbSize = sizeof( mii);
4441 ret = GetMenuItemInfo_common (hmenu, item, bypos,
4442 (LPMENUITEMINFOW)&mii, FALSE);
4443 mii.cbSize = lpmii->cbSize;
4444 memcpy( lpmii, &mii, mii.cbSize);
4448 /**********************************************************************
4449 * GetMenuItemInfoW (USER32.@)
4451 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4452 LPMENUITEMINFOW lpmii)
4456 if( lpmii->cbSize != sizeof( mii) &&
4457 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4458 SetLastError( ERROR_INVALID_PARAMETER);
4461 memcpy( &mii, lpmii, lpmii->cbSize);
4462 mii.cbSize = sizeof( mii);
4463 ret = GetMenuItemInfo_common (hmenu, item, bypos, &mii, TRUE);
4464 mii.cbSize = lpmii->cbSize;
4465 memcpy( lpmii, &mii, mii.cbSize);
4470 /* set a menu item text from a ASCII or Unicode string */
4471 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4477 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4478 strcpyW( menu->text, text );
4482 LPCSTR str = (LPCSTR)text;
4483 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4484 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4485 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4490 /**********************************************************************
4491 * SetMenuItemInfo_common
4494 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4495 const MENUITEMINFOW *lpmii,
4498 if (!menu) return FALSE;
4500 debug_print_menuitem("SetmenuItemInfo_common from: ", menu, "");
4502 if (lpmii->fMask & MIIM_TYPE ) {
4503 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4504 WARN("invalid combination of fMask bits used\n");
4505 /* this does not happen on Win9x/ME */
4506 SetLastError( ERROR_INVALID_PARAMETER);
4509 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4510 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4511 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4513 if (IS_STRING_ITEM(menu->fType)) {
4514 HeapFree(GetProcessHeap(), 0, menu->text);
4515 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4516 } else if( (menu->fType) & MFT_BITMAP)
4517 menu->hbmpItem = (HBITMAP)lpmii->dwTypeData;
4520 if (lpmii->fMask & MIIM_FTYPE ) {
4521 if(( lpmii->fType & MFT_BITMAP)) {
4522 SetLastError( ERROR_INVALID_PARAMETER);
4525 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4526 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4528 if (lpmii->fMask & MIIM_STRING ) {
4529 /* free the string when used */
4530 HeapFree(GetProcessHeap(), 0, menu->text);
4531 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4534 if (lpmii->fMask & MIIM_STATE)
4536 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4537 menu->fState = lpmii->fState;
4540 if (lpmii->fMask & MIIM_ID)
4541 menu->wID = lpmii->wID;
4543 if (lpmii->fMask & MIIM_SUBMENU) {
4544 menu->hSubMenu = lpmii->hSubMenu;
4545 if (menu->hSubMenu) {
4546 POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
4548 subMenu->wFlags |= MF_POPUP;
4549 menu->fType |= MF_POPUP;
4552 SetLastError( ERROR_INVALID_PARAMETER);
4557 menu->fType &= ~MF_POPUP;
4560 if (lpmii->fMask & MIIM_CHECKMARKS)
4562 if (lpmii->fType & MFT_RADIOCHECK)
4563 menu->fType |= MFT_RADIOCHECK;
4565 menu->hCheckBit = lpmii->hbmpChecked;
4566 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4568 if (lpmii->fMask & MIIM_DATA)
4569 menu->dwItemData = lpmii->dwItemData;
4571 if (lpmii->fMask & MIIM_BITMAP)
4572 menu->hbmpItem = lpmii->hbmpItem;
4574 if( !menu->text && !(menu->fType & MFT_OWNERDRAW) && !menu->hbmpItem)
4575 menu->fType |= MFT_SEPARATOR;
4577 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4581 /**********************************************************************
4582 * SetMenuItemInfoA (USER32.@)
4584 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4585 const MENUITEMINFOA *lpmii)
4588 if( lpmii->cbSize != sizeof( mii) &&
4589 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4590 SetLastError( ERROR_INVALID_PARAMETER);
4593 memcpy( &mii, lpmii, lpmii->cbSize);
4594 if( lpmii->cbSize != sizeof( mii)) {
4595 mii.cbSize = sizeof( mii);
4596 mii.hbmpItem = NULL;
4598 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4599 (const MENUITEMINFOW *)&mii, FALSE);
4602 /**********************************************************************
4603 * SetMenuItemInfoW (USER32.@)
4605 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4606 const MENUITEMINFOW *lpmii)
4609 if( lpmii->cbSize != sizeof( mii) &&
4610 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4611 SetLastError( ERROR_INVALID_PARAMETER);
4614 memcpy( &mii, lpmii, lpmii->cbSize);
4615 if( lpmii->cbSize != sizeof( mii)) {
4616 mii.cbSize = sizeof( mii);
4617 mii.hbmpItem = NULL;
4619 return SetMenuItemInfo_common(MENU_FindItem(&hmenu,
4620 &item, bypos? MF_BYPOSITION : 0), &mii, TRUE);
4623 /**********************************************************************
4624 * SetMenuDefaultItem (USER32.@)
4627 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4633 TRACE("(%p,%d,%d)\n", hmenu, uItem, bypos);
4635 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4637 /* reset all default-item flags */
4639 for (i = 0; i < menu->nItems; i++, item++)
4641 item->fState &= ~MFS_DEFAULT;
4644 /* no default item */
4653 if ( uItem >= menu->nItems ) return FALSE;
4654 item[uItem].fState |= MFS_DEFAULT;
4659 for (i = 0; i < menu->nItems; i++, item++)
4661 if (item->wID == uItem)
4663 item->fState |= MFS_DEFAULT;
4672 /**********************************************************************
4673 * GetMenuDefaultItem (USER32.@)
4675 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4681 TRACE("(%p,%d,%d)\n", hmenu, bypos, flags);
4683 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4685 /* find default item */
4689 if (! item) return -1;
4691 while ( !( item->fState & MFS_DEFAULT ) )
4694 if (i >= menu->nItems ) return -1;
4697 /* default: don't return disabled items */
4698 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4700 /* search rekursiv when needed */
4701 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4704 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4705 if ( -1 != ret ) return ret;
4707 /* when item not found in submenu, return the popup item */
4709 return ( bypos ) ? i : item->wID;
4714 /**********************************************************************
4715 * InsertMenuItemA (USER32.@)
4717 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4718 const MENUITEMINFOA *lpmii)
4720 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4722 if( lpmii->cbSize != sizeof( mii) &&
4723 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4724 SetLastError( ERROR_INVALID_PARAMETER);
4727 memcpy( &mii, lpmii, lpmii->cbSize);
4728 if( lpmii->cbSize != sizeof( mii)) {
4729 mii.cbSize = sizeof( mii);
4730 mii.hbmpItem = NULL;
4732 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)&mii, FALSE);
4736 /**********************************************************************
4737 * InsertMenuItemW (USER32.@)
4739 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4740 const MENUITEMINFOW *lpmii)
4742 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4744 if( lpmii->cbSize != sizeof( mii) &&
4745 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4746 SetLastError( ERROR_INVALID_PARAMETER);
4749 memcpy( &mii, lpmii, lpmii->cbSize);
4750 if( lpmii->cbSize != sizeof( mii)) {
4751 mii.cbSize = sizeof( mii);
4752 mii.hbmpItem = NULL;
4754 return SetMenuItemInfo_common(item, &mii, TRUE);
4757 /**********************************************************************
4758 * CheckMenuRadioItem (USER32.@)
4761 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4762 UINT first, UINT last, UINT check,
4765 MENUITEM *mifirst, *milast, *micheck;
4766 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4768 TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos);
4770 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4771 milast = MENU_FindItem (&mlast, &last, bypos);
4772 micheck = MENU_FindItem (&mcheck, &check, bypos);
4774 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4775 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4776 micheck > milast || micheck < mifirst)
4779 while (mifirst <= milast)
4781 if (mifirst == micheck)
4783 mifirst->fType |= MFT_RADIOCHECK;
4784 mifirst->fState |= MFS_CHECKED;
4786 mifirst->fType &= ~MFT_RADIOCHECK;
4787 mifirst->fState &= ~MFS_CHECKED;
4796 /**********************************************************************
4797 * GetMenuItemRect (USER32.@)
4799 * ATTENTION: Here, the returned values in rect are the screen
4800 * coordinates of the item just like if the menu was
4801 * always on the upper left side of the application.
4804 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4807 POPUPMENU *itemMenu;
4811 TRACE("(%p,%p,%d,%p)\n", hwnd, hMenu, uItem, rect);
4813 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4814 referenceHwnd = hwnd;
4818 itemMenu = MENU_GetMenu(hMenu);
4819 if (itemMenu == NULL)
4822 if(itemMenu->hWnd == 0)
4824 referenceHwnd = itemMenu->hWnd;
4827 if ((rect == NULL) || (item == NULL))
4832 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4838 /**********************************************************************
4839 * SetMenuInfo (USER32.@)
4842 * MIM_APPLYTOSUBMENUS
4843 * actually use the items to draw the menu
4845 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4849 TRACE("(%p %p)\n", hMenu, lpmi);
4851 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4854 if (lpmi->fMask & MIM_BACKGROUND)
4855 menu->hbrBack = lpmi->hbrBack;
4857 if (lpmi->fMask & MIM_HELPID)
4858 menu->dwContextHelpID = lpmi->dwContextHelpID;
4860 if (lpmi->fMask & MIM_MAXHEIGHT)
4861 menu->cyMax = lpmi->cyMax;
4863 if (lpmi->fMask & MIM_MENUDATA)
4864 menu->dwMenuData = lpmi->dwMenuData;
4866 if (lpmi->fMask & MIM_STYLE)
4868 menu->dwStyle = lpmi->dwStyle;
4869 if (menu->dwStyle & MNS_AUTODISMISS) FIXME("MNS_AUTODISMISS unimplemented\n");
4870 if (menu->dwStyle & MNS_DRAGDROP) FIXME("MNS_DRAGDROP unimplemented\n");
4871 if (menu->dwStyle & MNS_MODELESS) FIXME("MNS_MODELESS unimplemented\n");
4872 if (menu->dwStyle & MNS_NOCHECK) FIXME("MNS_NOCHECK unimplemented\n");
4873 if (menu->dwStyle & MNS_NOTIFYBYPOS) FIXME("MNS_NOTIFYBYPOS unimplemented\n");
4881 /**********************************************************************
4882 * GetMenuInfo (USER32.@)
4888 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4891 TRACE("(%p %p)\n", hMenu, lpmi);
4893 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4896 if (lpmi->fMask & MIM_BACKGROUND)
4897 lpmi->hbrBack = menu->hbrBack;
4899 if (lpmi->fMask & MIM_HELPID)
4900 lpmi->dwContextHelpID = menu->dwContextHelpID;
4902 if (lpmi->fMask & MIM_MAXHEIGHT)
4903 lpmi->cyMax = menu->cyMax;
4905 if (lpmi->fMask & MIM_MENUDATA)
4906 lpmi->dwMenuData = menu->dwMenuData;
4908 if (lpmi->fMask & MIM_STYLE)
4909 lpmi->dwStyle = menu->dwStyle;
4917 /**********************************************************************
4918 * SetMenuContextHelpId (USER32.@)
4920 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4924 TRACE("(%p 0x%08lx)\n", hMenu, dwContextHelpID);
4926 if ((menu = MENU_GetMenu(hMenu)))
4928 menu->dwContextHelpID = dwContextHelpID;
4935 /**********************************************************************
4936 * GetMenuContextHelpId (USER32.@)
4938 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4942 TRACE("(%p)\n", hMenu);
4944 if ((menu = MENU_GetMenu(hMenu)))
4946 return menu->dwContextHelpID;
4951 /**********************************************************************
4952 * MenuItemFromPoint (USER32.@)
4954 INT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4956 POPUPMENU *menu = MENU_GetMenu(hMenu);
4959 /*FIXME: Do we have to handle hWnd here? */
4960 if (!menu) return -1;
4961 if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
4966 /**********************************************************************
4967 * translate_accelerator
4969 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4970 BYTE fVirt, WORD key, WORD cmd )
4975 if (wParam != key) return FALSE;
4977 if (GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4978 if (GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4979 if (GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4981 if (message == WM_CHAR || message == WM_SYSCHAR)
4983 if ( !(fVirt & FVIRTKEY) && (mask & FALT) == (fVirt & FALT) )
4985 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4991 if(fVirt & FVIRTKEY)
4993 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4994 wParam, 0xff & HIWORD(lParam));
4996 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4997 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
5001 if (!(lParam & 0x01000000)) /* no special_key */
5003 if ((fVirt & FALT) && (lParam & 0x20000000))
5004 { /* ^^ ALT pressed */
5005 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
5014 if (message == WM_KEYUP || message == WM_SYSKEYUP)
5018 HMENU hMenu, hSubMenu, hSysMenu;
5019 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
5021 hMenu = (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
5022 hSysMenu = get_win_sys_menu( hWnd );
5024 /* find menu item and ask application to initialize it */
5025 /* 1. in the system menu */
5026 hSubMenu = hSysMenu;
5028 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5032 if (!IsWindowEnabled(hWnd))
5036 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
5037 if(hSubMenu != hSysMenu)
5039 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
5040 TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
5041 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
5043 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
5046 else /* 2. in the window's menu */
5050 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5054 if (!IsWindowEnabled(hWnd))
5058 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
5059 if(hSubMenu != hMenu)
5061 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
5062 TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
5063 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
5065 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
5072 if (uSysStat != (UINT)-1)
5074 if (uSysStat & (MF_DISABLED|MF_GRAYED))
5081 if (uStat != (UINT)-1)
5087 if (uStat & (MF_DISABLED|MF_GRAYED))
5099 if( mesg==WM_COMMAND )
5101 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
5102 SendMessageW(hWnd, mesg, 0x10000 | cmd, 0L);
5104 else if( mesg==WM_SYSCOMMAND )
5106 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
5107 SendMessageW(hWnd, mesg, cmd, 0x00010000L);
5111 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5112 * #0: unknown (please report!)
5113 * #1: for WM_KEYUP,WM_SYSKEYUP
5114 * #2: mouse is captured
5115 * #3: window is disabled
5116 * #4: it's a disabled system menu option
5117 * #5: it's a menu option, but window is iconic
5118 * #6: it's a menu option, but disabled
5120 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
5122 ERR_(accel)(" unknown reason - please report!\n");
5127 /**********************************************************************
5128 * TranslateAcceleratorA (USER32.@)
5129 * TranslateAccelerator (USER32.@)
5131 INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg )
5134 LPACCEL16 lpAccelTbl;
5138 if (!hWnd || !msg) return 0;
5140 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5142 WARN_(accel)("invalid accel handle=%p\n", hAccel);
5146 wParam = msg->wParam;
5148 switch (msg->message)
5157 char ch = LOWORD(wParam);
5159 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
5160 wParam = MAKEWPARAM(wch, HIWORD(wParam));
5168 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
5169 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5173 if (translate_accelerator( hWnd, msg->message, wParam, msg->lParam,
5174 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5176 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5181 /**********************************************************************
5182 * TranslateAcceleratorW (USER32.@)
5184 INT WINAPI TranslateAcceleratorW( HWND hWnd, HACCEL hAccel, LPMSG msg )
5187 LPACCEL16 lpAccelTbl;
5190 if (!hWnd || !msg) return 0;
5192 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5194 WARN_(accel)("invalid accel handle=%p\n", hAccel);
5198 switch (msg->message)
5210 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
5211 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5215 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5216 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5218 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);