4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Note: the style MF_MOUSESELECT is used to mark popup items that
25 * have been selected, i.e. their popup menu is currently displayed.
26 * This is probably not the meaning this style has in MS-Windows.
30 #include "wine/port.h"
39 #include "wine/winbase16.h"
40 #include "wine/winuser16.h"
42 #include "wine/server.h"
43 #include "wine/unicode.h"
46 #include "user_private.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(menu);
50 WINE_DECLARE_DEBUG_CHANNEL(accel);
52 /* internal popup menu window messages */
54 #define MM_SETMENUHANDLE (WM_USER + 0)
55 #define MM_GETMENUHANDLE (WM_USER + 1)
57 /* Menu item structure */
59 /* ----------- MENUITEMINFO Stuff ----------- */
60 UINT fType; /* Item type. */
61 UINT fState; /* Item state. */
62 UINT_PTR wID; /* Item id. */
63 HMENU hSubMenu; /* Pop-up menu. */
64 HBITMAP hCheckBit; /* Bitmap when checked. */
65 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
66 LPWSTR text; /* Item text or bitmap handle. */
67 DWORD dwItemData; /* Application defined. */
68 DWORD dwTypeData; /* depends on fMask */
69 HBITMAP hbmpItem; /* bitmap in win98 style menus */
70 /* ----------- Wine stuff ----------- */
71 RECT rect; /* Item area (relative to menu window) */
72 UINT xTab; /* X position of text after Tab */
75 /* Popup menu structure */
77 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
78 WORD wMagic; /* Magic number */
79 WORD Width; /* Width of the whole menu */
80 WORD Height; /* Height of the whole menu */
81 UINT nItems; /* Number of items in the menu */
82 HWND hWnd; /* Window containing the menu */
83 MENUITEM *items; /* Array of menu items */
84 UINT FocusedItem; /* Currently focused item */
85 HWND hwndOwner; /* window receiving the messages for ownerdraw */
86 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
87 /* ------------ MENUINFO members ------ */
88 DWORD dwStyle; /* Extended mennu style */
89 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
90 HBRUSH hbrBack; /* brush for menu background */
91 DWORD dwContextHelpID;
92 DWORD dwMenuData; /* application defined value */
93 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
94 } POPUPMENU, *LPPOPUPMENU;
96 /* internal flags for menu tracking */
98 #define TF_ENDMENU 0x0001
99 #define TF_SUSPENDPOPUP 0x0002
100 #define TF_SKIPREMOVE 0x0004
105 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
106 HMENU hTopMenu; /* initial menu */
107 HWND hOwnerWnd; /* where notifications are sent */
111 #define MENU_MAGIC 0x554d /* 'MU' */
116 /* Internal MENU_TrackMenu() flags */
117 #define TPM_INTERNAL 0xF0000000
118 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
119 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
120 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
122 /* popup menu shade thickness */
123 #define POPUP_XSHADE 4
124 #define POPUP_YSHADE 4
126 /* Space between 2 menu bar items */
127 #define MENU_BAR_ITEMS_SPACE 12
129 /* Minimum width of a tab character */
130 #define MENU_TAB_SPACE 8
132 /* Height of a separator item */
133 #define SEPARATOR_HEIGHT 5
135 /* (other menu->FocusedItem values give the position of the focused item) */
136 #define NO_SELECTED_ITEM 0xffff
138 #define MENU_ITEM_TYPE(flags) \
139 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
141 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
142 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
143 #define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
145 #define IS_SYSTEM_MENU(menu) \
146 (!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
148 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
149 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
150 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
151 MF_POPUP | MF_SYSMENU | MF_HELP)
152 #define STATE_MASK (~TYPE_MASK)
154 /* Dimension of the menu bitmaps */
155 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
157 static HBITMAP hStdMnArrow = 0;
158 static HBITMAP hBmpSysMenu = 0;
160 static HBRUSH hShadeBrush = 0;
161 static HFONT hMenuFont = 0;
162 static HFONT hMenuFontBold = 0;
164 static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
166 /* Use global popup window because there's no way 2 menus can
167 * be tracked at the same time. */
168 static HWND top_popup;
170 /* Flag set by EndMenu() to force an exit from menu tracking */
171 static BOOL fEndMenu = FALSE;
173 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
175 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont);
177 /*********************************************************************
178 * menu class descriptor
180 const struct builtin_class_descr MENU_builtin_class =
182 POPUPMENU_CLASS_ATOMA, /* name */
183 CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, /* style */
184 NULL, /* procA (winproc is Unicode only) */
185 PopupMenuWndProc, /* procW */
186 sizeof(HMENU), /* extra */
187 IDC_ARROW, /* cursor */
188 (HBRUSH)(COLOR_MENU+1) /* brush */
192 /***********************************************************************
193 * debug_print_menuitem
195 * Print a menuitem in readable form.
198 #define debug_print_menuitem(pre, mp, post) \
199 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
201 #define MENUOUT(text) \
202 DPRINTF("%s%s", (count++ ? "," : ""), (text))
204 #define MENUFLAG(bit,text) \
206 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
209 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
212 TRACE("%s ", prefix);
214 UINT flags = mp->fType;
215 int type = MENU_ITEM_TYPE(flags);
216 DPRINTF( "{ ID=0x%x", mp->wID);
217 if (flags & MF_POPUP)
218 DPRINTF( ", Sub=%p", mp->hSubMenu);
222 if (type == MFT_STRING)
224 else if (type == MFT_SEPARATOR)
226 else if (type == MFT_OWNERDRAW)
228 else if (type == MFT_BITMAP)
234 MENUFLAG(MF_POPUP, "pop");
235 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
236 MENUFLAG(MFT_MENUBREAK, "brk");
237 MENUFLAG(MFT_RADIOCHECK, "radio");
238 MENUFLAG(MFT_RIGHTORDER, "rorder");
239 MENUFLAG(MF_SYSMENU, "sys");
240 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
243 DPRINTF( "+0x%x", flags);
248 DPRINTF( ", State=");
249 MENUFLAG(MFS_GRAYED, "grey");
250 MENUFLAG(MFS_DEFAULT, "default");
251 MENUFLAG(MFS_DISABLED, "dis");
252 MENUFLAG(MFS_CHECKED, "check");
253 MENUFLAG(MFS_HILITE, "hi");
254 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
255 MENUFLAG(MF_MOUSESELECT, "mouse");
257 DPRINTF( "+0x%x", flags);
260 DPRINTF( ", Chk=%p", mp->hCheckBit);
262 DPRINTF( ", Unc=%p", mp->hUnCheckBit);
264 if (type == MFT_STRING) {
266 DPRINTF( ", Text=%s", debugstr_w(mp->text));
268 DPRINTF( ", Text=Null");
269 } else if (mp->text == NULL)
272 DPRINTF( ", Text=%p", mp->text);
274 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
280 DPRINTF(" %s\n", postfix);
287 /***********************************************************************
290 * Validate the given menu handle and returns the menu structure pointer.
292 static POPUPMENU *MENU_GetMenu(HMENU hMenu)
294 POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
295 if (!menu || menu->wMagic != MENU_MAGIC)
297 WARN("invalid menu handle=%p, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
303 /***********************************************************************
306 * Get the system menu of a window
308 static HMENU get_win_sys_menu( HWND hwnd )
311 WND *win = WIN_GetPtr( hwnd );
312 if (win && win != WND_OTHER_PROCESS)
315 WIN_ReleasePtr( win );
320 /***********************************************************************
323 * Return the default system menu.
325 static HMENU MENU_CopySysPopup(void)
327 static const WCHAR sysmenuW[] = {'S','Y','S','M','E','N','U',0};
328 HMENU hMenu = LoadMenuW(user32_module, sysmenuW);
331 POPUPMENU* menu = MENU_GetMenu(hMenu);
332 menu->wFlags |= MF_SYSMENU | MF_POPUP;
333 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
336 ERR("Unable to load default system menu\n" );
338 TRACE("returning %p.\n", hMenu );
344 /**********************************************************************
347 * Create a copy of the system menu. System menu in Windows is
348 * a special menu bar with the single entry - system menu popup.
349 * This popup is presented to the outside world as a "system menu".
350 * However, the real system menu handle is sometimes seen in the
351 * WM_MENUSELECT parameters (and Word 6 likes it this way).
353 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
357 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd, hPopupMenu);
358 if ((hMenu = CreateMenu()))
360 POPUPMENU *menu = MENU_GetMenu(hMenu);
361 menu->wFlags = MF_SYSMENU;
362 menu->hWnd = WIN_GetFullHandle( hWnd );
363 TRACE("hWnd %p (hMenu %p)\n", menu->hWnd, hMenu);
365 if (hPopupMenu == (HMENU)(-1))
366 hPopupMenu = MENU_CopySysPopup();
367 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
371 InsertMenuW( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION,
372 (UINT_PTR)hPopupMenu, NULL );
374 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
375 menu->items[0].fState = 0;
376 if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
378 TRACE("hMenu=%p (hPopup %p)\n", hMenu, hPopupMenu );
381 DestroyMenu( hMenu );
383 ERR("failed to load system menu!\n");
388 /***********************************************************************
391 * Menus initialisation.
396 NONCLIENTMETRICSW ncm;
398 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
403 /* Load menu bitmaps */
404 hStdMnArrow = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
405 /* Load system buttons bitmaps */
406 hBmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
411 GetObjectW( hStdMnArrow, sizeof(bm), &bm );
412 arrow_bitmap_width = bm.bmWidth;
413 arrow_bitmap_height = bm.bmHeight;
417 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
420 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
423 DeleteObject( hBitmap );
424 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
427 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
428 if (!(SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0)))
431 if (!(hMenuFont = CreateFontIndirectW( &ncm.lfMenuFont )))
434 ncm.lfMenuFont.lfWeight += 300;
435 if ( ncm.lfMenuFont.lfWeight > 1000)
436 ncm.lfMenuFont.lfWeight = 1000;
438 if (!(hMenuFontBold = CreateFontIndirectW( &ncm.lfMenuFont )))
444 /***********************************************************************
445 * MENU_InitSysMenuPopup
447 * Grey the appropriate items in System menu.
449 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
453 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
454 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
455 gray = ((style & WS_MAXIMIZE) != 0);
456 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
457 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
458 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
459 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
460 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
461 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
462 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
463 gray = (clsStyle & CS_NOCLOSE) != 0;
465 /* The menu item must keep its state if it's disabled */
467 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
471 /******************************************************************************
473 * UINT MENU_GetStartOfNextColumn(
476 *****************************************************************************/
478 static UINT MENU_GetStartOfNextColumn(
481 POPUPMENU *menu = MENU_GetMenu(hMenu);
485 return NO_SELECTED_ITEM;
487 i = menu->FocusedItem + 1;
488 if( i == NO_SELECTED_ITEM )
491 for( ; i < menu->nItems; ++i ) {
492 if (menu->items[i].fType & MF_MENUBARBREAK)
496 return NO_SELECTED_ITEM;
500 /******************************************************************************
502 * UINT MENU_GetStartOfPrevColumn(
505 *****************************************************************************/
507 static UINT MENU_GetStartOfPrevColumn(
510 POPUPMENU *menu = MENU_GetMenu(hMenu);
514 return NO_SELECTED_ITEM;
516 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
517 return NO_SELECTED_ITEM;
519 /* Find the start of the column */
521 for(i = menu->FocusedItem; i != 0 &&
522 !(menu->items[i].fType & MF_MENUBARBREAK);
526 return NO_SELECTED_ITEM;
528 for(--i; i != 0; --i) {
529 if (menu->items[i].fType & MF_MENUBARBREAK)
533 TRACE("ret %d.\n", i );
540 /***********************************************************************
543 * Find a menu item. Return a pointer on the item, and modifies *hmenu
544 * in case the item was in a sub-menu.
546 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
551 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
552 if (wFlags & MF_BYPOSITION)
554 if (*nPos >= menu->nItems) return NULL;
555 return &menu->items[*nPos];
559 MENUITEM *item = menu->items;
560 for (i = 0; i < menu->nItems; i++, item++)
562 if (item->wID == *nPos)
567 else if (item->fType & MF_POPUP)
569 HMENU hsubmenu = item->hSubMenu;
570 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
582 /***********************************************************************
585 * Find a Sub menu. Return the position of the submenu, and modifies
586 * *hmenu in case it is found in another sub-menu.
587 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
589 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
594 if (((*hmenu)==(HMENU)0xffff) ||
595 (!(menu = MENU_GetMenu(*hmenu))))
596 return NO_SELECTED_ITEM;
598 for (i = 0; i < menu->nItems; i++, item++) {
599 if(!(item->fType & MF_POPUP)) continue;
600 if (item->hSubMenu == hSubTarget) {
604 HMENU hsubmenu = item->hSubMenu;
605 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
606 if (pos != NO_SELECTED_ITEM) {
612 return NO_SELECTED_ITEM;
615 /***********************************************************************
618 static void MENU_FreeItemData( MENUITEM* item )
621 if (IS_STRING_ITEM(item->fType) && item->text)
622 HeapFree( GetProcessHeap(), 0, item->text );
625 /***********************************************************************
626 * MENU_FindItemByCoords
628 * Find the item at the specified coordinates (screen coords). Does
629 * not work for child windows and therefore should not be called for
630 * an arbitrary system menu.
632 static MENUITEM *MENU_FindItemByCoords( const POPUPMENU *menu,
633 POINT pt, UINT *pos )
639 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
640 pt.x -= wrect.left;pt.y -= wrect.top;
642 for (i = 0; i < menu->nItems; i++, item++)
644 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
645 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
655 /***********************************************************************
658 * Find the menu item selected by a key press.
659 * Return item id, -1 if none, -2 if we should close the menu.
661 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
662 WCHAR key, BOOL forceMenuChar )
664 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)key, key, hmenu );
666 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
670 POPUPMENU *menu = MENU_GetMenu( hmenu );
671 MENUITEM *item = menu->items;
678 for (i = 0; i < menu->nItems; i++, item++)
680 if (IS_STRING_ITEM(item->fType) && item->text)
682 WCHAR *p = item->text - 2;
685 p = strchrW (p + 2, '&');
687 while (p != NULL && p [1] == '&');
688 if (p && (toupperW(p[1]) == toupperW(key))) return i;
692 menuchar = SendMessageW( hwndOwner, WM_MENUCHAR,
693 MAKEWPARAM( key, menu->wFlags ), (LPARAM)hmenu );
694 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
695 if (HIWORD(menuchar) == 1) return (UINT)(-2);
701 /***********************************************************************
702 * MENU_GetBitmapItemSize
704 * Get the size of a bitmap item.
706 static void MENU_GetBitmapItemSize( UINT id, DWORD data, SIZE *size )
709 HBITMAP bmp = (HBITMAP)id;
711 size->cx = size->cy = 0;
713 /* check if there is a magic menu item associated with this item */
714 if (id && IS_MAGIC_ITEM( id ))
718 case (INT_PTR)HBMMENU_SYSTEM:
725 case (INT_PTR)HBMMENU_MBAR_RESTORE:
726 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
727 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
728 case (INT_PTR)HBMMENU_MBAR_CLOSE:
729 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
730 size->cx = GetSystemMetrics( SM_CYMENU ) - 4;
733 case (INT_PTR)HBMMENU_CALLBACK:
734 case (INT_PTR)HBMMENU_POPUP_CLOSE:
735 case (INT_PTR)HBMMENU_POPUP_RESTORE:
736 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
737 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
739 FIXME("Magic 0x%08x not implemented\n", id);
743 if (GetObjectW(bmp, sizeof(bm), &bm ))
745 size->cx = bm.bmWidth;
746 size->cy = bm.bmHeight;
750 /***********************************************************************
751 * MENU_DrawBitmapItem
753 * Draw a bitmap item.
755 static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar )
760 HBITMAP bmp = (HBITMAP)lpitem->text;
761 int w = rect->right - rect->left;
762 int h = rect->bottom - rect->top;
766 /* Check if there is a magic menu item associated with this item */
767 if (lpitem->text && IS_MAGIC_ITEM(lpitem->text))
772 switch(LOWORD(lpitem->text))
774 case (INT_PTR)HBMMENU_SYSTEM:
775 if (lpitem->dwItemData)
777 bmp = (HBITMAP)lpitem->dwItemData;
778 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
783 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
784 /* only use right half of the bitmap */
785 bmp_xoffset = bm.bmWidth / 2;
786 bm.bmWidth -= bmp_xoffset;
789 case (INT_PTR)HBMMENU_MBAR_RESTORE:
790 flags = DFCS_CAPTIONRESTORE;
792 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
793 flags = DFCS_CAPTIONMIN;
795 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
796 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
798 case (INT_PTR)HBMMENU_MBAR_CLOSE:
799 flags = DFCS_CAPTIONCLOSE;
801 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
802 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
804 case (INT_PTR)HBMMENU_CALLBACK:
805 case (INT_PTR)HBMMENU_POPUP_CLOSE:
806 case (INT_PTR)HBMMENU_POPUP_RESTORE:
807 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
808 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
810 FIXME("Magic 0x%08x not implemented\n", LOWORD(lpitem->text));
814 InflateRect( &r, -1, -1 );
815 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
816 DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
820 if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
823 hdcMem = CreateCompatibleDC( hdc );
824 SelectObject( hdcMem, bmp );
826 /* handle fontsize > bitmap_height */
827 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
829 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text)) ? NOTSRCCOPY : SRCCOPY;
830 if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
831 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
832 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
837 /***********************************************************************
840 * Calculate the size of the menu item and store it in lpitem->rect.
842 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
843 INT orgX, INT orgY, BOOL menuBar )
846 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
848 TRACE("dc=%p owner=%p (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
849 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
850 (menuBar ? " (MenuBar)" : ""));
852 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
854 if (lpitem->fType & MF_OWNERDRAW)
857 ** Experimentation under Windows reveals that an owner-drawn
858 ** menu is expected to return the size of the content part of
859 ** the menu item, not including the checkmark nor the submenu
860 ** arrow. Windows adds those values itself and returns the
861 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
863 MEASUREITEMSTRUCT mis;
864 mis.CtlType = ODT_MENU;
866 mis.itemID = lpitem->wID;
867 mis.itemData = (DWORD)lpitem->dwItemData;
870 SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
871 lpitem->rect.right += mis.itemWidth;
875 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
878 /* under at least win95 you seem to be given a standard
879 height for the menu and the height value is ignored */
880 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
883 lpitem->rect.bottom += mis.itemHeight;
885 TRACE("id=%04x size=%dx%d\n",
886 lpitem->wID, mis.itemWidth, mis.itemHeight);
887 /* Fall through to get check/arrow width calculation. */
890 if (lpitem->fType & MF_SEPARATOR)
892 lpitem->rect.bottom += SEPARATOR_HEIGHT;
898 lpitem->rect.right += 2 * check_bitmap_width;
899 if (lpitem->fType & MF_POPUP)
900 lpitem->rect.right += arrow_bitmap_width;
903 if (lpitem->fType & MF_OWNERDRAW)
906 if (IS_BITMAP_ITEM(lpitem->fType))
910 MENU_GetBitmapItemSize( (int)lpitem->text, lpitem->dwItemData, &size );
911 lpitem->rect.right += size.cx;
912 lpitem->rect.bottom += size.cy;
913 /* Leave space for the sunken border */
914 lpitem->rect.right += 2;
915 lpitem->rect.bottom += 2;
919 /* it must be a text item - unless it's the system menu */
920 if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
923 GetTextExtentPoint32W(hdc, lpitem->text, strlenW(lpitem->text), &size);
925 lpitem->rect.right += size.cx;
926 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
931 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
933 else if ((p = strchrW( lpitem->text, '\t' )) != NULL)
935 /* Item contains a tab (only meaningful in popup menus) */
936 GetTextExtentPoint32W(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
937 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
938 lpitem->rect.right += MENU_TAB_SPACE;
942 if (strchrW( lpitem->text, '\b' ))
943 lpitem->rect.right += MENU_TAB_SPACE;
944 lpitem->xTab = lpitem->rect.right - check_bitmap_width
945 - arrow_bitmap_width;
948 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
952 /***********************************************************************
953 * MENU_PopupMenuCalcSize
955 * Calculate the size of a popup menu.
957 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
962 int orgX, orgY, maxX, maxTab, maxTabWidth;
964 lppop->Width = lppop->Height = 0;
965 if (lppop->nItems == 0) return;
968 SelectObject( hdc, hMenuFont);
973 while (start < lppop->nItems)
975 lpitem = &lppop->items[start];
979 maxTab = maxTabWidth = 0;
981 /* Parse items until column break or end of menu */
982 for (i = start; i < lppop->nItems; i++, lpitem++)
985 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
987 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
989 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
990 maxX = max( maxX, lpitem->rect.right );
991 orgY = lpitem->rect.bottom;
992 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
994 maxTab = max( maxTab, lpitem->xTab );
995 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
999 /* Finish the column (set all items to the largest width found) */
1000 maxX = max( maxX, maxTab + maxTabWidth );
1001 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
1003 lpitem->rect.right = maxX;
1004 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1005 lpitem->xTab = maxTab;
1008 lppop->Height = max( lppop->Height, orgY );
1011 lppop->Width = maxX;
1013 /* space for 3d border */
1017 ReleaseDC( 0, hdc );
1021 /***********************************************************************
1022 * MENU_MenuBarCalcSize
1024 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1025 * height is off by 1 pixel which causes lengthy window relocations when
1026 * active document window is maximized/restored.
1028 * Calculate the size of the menu bar.
1030 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1031 LPPOPUPMENU lppop, HWND hwndOwner )
1034 int start, i, orgX, orgY, maxY, helpPos;
1036 if ((lprect == NULL) || (lppop == NULL)) return;
1037 if (lppop->nItems == 0) return;
1038 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1039 lprect->left, lprect->top, lprect->right, lprect->bottom);
1040 lppop->Width = lprect->right - lprect->left;
1042 maxY = lprect->top+1;
1045 while (start < lppop->nItems)
1047 lpitem = &lppop->items[start];
1048 orgX = lprect->left;
1051 /* Parse items until line break or end of menu */
1052 for (i = start; i < lppop->nItems; i++, lpitem++)
1054 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
1056 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1058 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1060 debug_print_menuitem (" item: ", lpitem, "");
1061 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1063 if (lpitem->rect.right > lprect->right)
1065 if (i != start) break;
1066 else lpitem->rect.right = lprect->right;
1068 maxY = max( maxY, lpitem->rect.bottom );
1069 orgX = lpitem->rect.right;
1072 /* Finish the line (set all items to the largest height found) */
1073 while (start < i) lppop->items[start++].rect.bottom = maxY;
1076 lprect->bottom = maxY;
1077 lppop->Height = lprect->bottom - lprect->top;
1079 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1080 /* the last item (if several lines, only move the last line) */
1081 lpitem = &lppop->items[lppop->nItems-1];
1082 orgY = lpitem->rect.top;
1083 orgX = lprect->right;
1084 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1085 if ( (helpPos==-1) || (helpPos>i) )
1087 if (lpitem->rect.top != orgY) break; /* Other line */
1088 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1089 lpitem->rect.left += orgX - lpitem->rect.right;
1090 lpitem->rect.right = orgX;
1091 orgX = lpitem->rect.left;
1095 /***********************************************************************
1098 * Draw a single menu item.
1100 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1101 UINT height, BOOL menuBar, UINT odaction )
1105 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1107 if (lpitem->fType & MF_SYSMENU)
1109 if( !IsIconic(hwnd) )
1110 NC_DrawSysButton( hwnd, hdc, lpitem->fState & (MF_HILITE | MF_MOUSESELECT) );
1116 if (lpitem->fState & MF_HILITE)
1119 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1120 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1122 if(lpitem->fState & MF_GRAYED)
1123 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1125 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1126 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1131 if (lpitem->fState & MF_GRAYED)
1132 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1134 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1135 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1138 if (lpitem->fType & MF_OWNERDRAW)
1141 ** Experimentation under Windows reveals that an owner-drawn
1142 ** menu is given the rectangle which includes the space it requested
1143 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1144 ** and a popup-menu arrow. This is the value of lpitem->rect.
1145 ** Windows will leave all drawing to the application except for
1146 ** the popup-menu arrow. Windows always draws that itself, after
1147 ** the menu owner has finished drawing.
1151 dis.CtlType = ODT_MENU;
1153 dis.itemID = lpitem->wID;
1154 dis.itemData = (DWORD)lpitem->dwItemData;
1156 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1157 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED|ODS_DISABLED;
1158 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1159 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1160 dis.hwndItem = (HWND)hmenu;
1162 dis.rcItem = lpitem->rect;
1163 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1164 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner,
1165 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1166 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1168 SendMessageW( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1169 /* Fall through to draw popup-menu arrow */
1172 TRACE("rect={%ld,%ld,%ld,%ld}\n", lpitem->rect.left, lpitem->rect.top,
1173 lpitem->rect.right,lpitem->rect.bottom);
1175 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1177 rect = lpitem->rect;
1179 if (!(lpitem->fType & MF_OWNERDRAW))
1181 if (lpitem->fState & MF_HILITE)
1184 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1186 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1189 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1192 SetBkMode( hdc, TRANSPARENT );
1194 if (!(lpitem->fType & MF_OWNERDRAW))
1196 /* vertical separator */
1197 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1201 rc.bottom = height - 3;
1202 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1205 /* horizontal separator */
1206 if (lpitem->fType & MF_SEPARATOR)
1211 rc.top += SEPARATOR_HEIGHT / 2;
1212 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1217 /* helper lines for debugging */
1218 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1219 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1220 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1221 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1226 INT y = rect.top + rect.bottom;
1227 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1228 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1230 if (!(lpitem->fType & MF_OWNERDRAW))
1232 /* Draw the check mark
1235 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1237 HBITMAP bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
1238 if (bm) /* we have a custom bitmap */
1240 HDC hdcMem = CreateCompatibleDC( hdc );
1241 SelectObject( hdcMem, bm );
1242 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1243 check_bitmap_width, check_bitmap_height,
1244 hdcMem, 0, 0, SRCCOPY );
1247 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1250 HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1251 HDC hdcMem = CreateCompatibleDC( hdc );
1252 SelectObject( hdcMem, bm );
1253 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
1254 DrawFrameControl( hdcMem, &r, DFC_MENU,
1255 (lpitem->fType & MFT_RADIOCHECK) ?
1256 DFCS_MENUBULLET : DFCS_MENUCHECK );
1257 BitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
1258 hdcMem, 0, 0, SRCCOPY );
1264 /* Draw the popup-menu arrow */
1265 if (lpitem->fType & MF_POPUP)
1267 HDC hdcMem = CreateCompatibleDC( hdc );
1268 HBITMAP hOrigBitmap;
1270 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1271 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1272 (y - arrow_bitmap_height) / 2,
1273 arrow_bitmap_width, arrow_bitmap_height,
1274 hdcMem, 0, 0, SRCCOPY );
1275 SelectObject( hdcMem, hOrigBitmap );
1279 rect.left += check_bitmap_width;
1280 rect.right -= arrow_bitmap_width;
1283 /* Done for owner-drawn */
1284 if (lpitem->fType & MF_OWNERDRAW)
1287 /* Draw the item text or bitmap */
1288 if (IS_BITMAP_ITEM(lpitem->fType))
1290 MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
1294 /* No bitmap - process text if present */
1295 else if (IS_STRING_ITEM(lpitem->fType))
1300 UINT uFormat = (menuBar) ?
1301 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1302 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1304 if ( lpitem->fState & MFS_DEFAULT )
1306 hfontOld = SelectObject( hdc, hMenuFontBold);
1311 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1312 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1315 for (i = 0; lpitem->text[i]; i++)
1316 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1319 if(lpitem->fState & MF_GRAYED)
1321 if (!(lpitem->fState & MF_HILITE) )
1323 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1324 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1325 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1326 --rect.left; --rect.top; --rect.right; --rect.bottom;
1328 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1331 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
1333 /* paint the shortcut text */
1334 if (!menuBar && lpitem->text[i]) /* There's a tab or flush-right char */
1336 if (lpitem->text[i] == '\t')
1338 rect.left = lpitem->xTab;
1339 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1343 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1346 if(lpitem->fState & MF_GRAYED)
1348 if (!(lpitem->fState & MF_HILITE) )
1350 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1351 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1352 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1353 --rect.left; --rect.top; --rect.right; --rect.bottom;
1355 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1357 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1361 SelectObject (hdc, hfontOld);
1366 /***********************************************************************
1367 * MENU_DrawPopupMenu
1369 * Paint a popup menu.
1371 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1373 HBRUSH hPrevBrush = 0;
1376 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
1378 GetClientRect( hwnd, &rect );
1380 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1381 && (SelectObject( hdc, hMenuFont)))
1385 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1387 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1392 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1394 /* draw menu items */
1396 menu = MENU_GetMenu( hmenu );
1397 if (menu && menu->nItems)
1402 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1403 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1404 menu->Height, FALSE, ODA_DRAWENTIRE );
1409 SelectObject( hdc, hPrevBrush );
1414 /***********************************************************************
1417 * Paint a menu bar. Returns the height of the menu bar.
1418 * called from [windows/nonclient.c]
1420 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1425 HMENU hMenu = GetMenu(hwnd);
1427 lppop = MENU_GetMenu( hMenu );
1428 if (lppop == NULL || lprect == NULL)
1430 return GetSystemMetrics(SM_CYMENU);
1435 hfontOld = SelectObject( hDC, hMenuFont);
1437 if (lppop->Height == 0)
1438 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1440 lprect->bottom = lprect->top + lppop->Height;
1442 if (hfontOld) SelectObject( hDC, hfontOld);
1443 return lppop->Height;
1446 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
1450 /***********************************************************************
1453 * Display a popup menu.
1455 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1456 INT x, INT y, INT xanchor, INT yanchor )
1461 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1462 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1464 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1465 if (menu->FocusedItem != NO_SELECTED_ITEM)
1467 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1468 menu->FocusedItem = NO_SELECTED_ITEM;
1471 /* store the owner for DrawItem */
1472 menu->hwndOwner = hwndOwner;
1474 MENU_PopupMenuCalcSize( menu, hwndOwner );
1476 /* adjust popup menu pos so that it fits within the desktop */
1478 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1479 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1481 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1484 x -= width - xanchor;
1485 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1486 x = GetSystemMetrics(SM_CXSCREEN) - width;
1490 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1493 y -= height + yanchor;
1494 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1495 y = GetSystemMetrics(SM_CYSCREEN) - height;
1499 /* NOTE: In Windows, top menu popup is not owned. */
1500 menu->hWnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL,
1501 WS_POPUP, x, y, width, height,
1502 hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
1504 if( !menu->hWnd ) return FALSE;
1505 if (!top_popup) top_popup = menu->hWnd;
1507 /* Display the window */
1509 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1510 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1511 UpdateWindow( menu->hWnd );
1516 /***********************************************************************
1519 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1520 BOOL sendMenuSelect, HMENU topmenu )
1525 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1527 lppop = MENU_GetMenu( hmenu );
1528 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
1530 if (lppop->FocusedItem == wIndex) return;
1531 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1532 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1533 if (!top_popup) top_popup = lppop->hWnd;
1535 SelectObject( hdc, hMenuFont);
1537 /* Clear previous highlighted item */
1538 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1540 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1541 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1542 lppop->Height, !(lppop->wFlags & MF_POPUP),
1546 /* Highlight new item (if any) */
1547 lppop->FocusedItem = wIndex;
1548 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1550 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1551 lppop->items[wIndex].fState |= MF_HILITE;
1552 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1553 &lppop->items[wIndex], lppop->Height,
1554 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1558 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1559 SendMessageW( hwndOwner, WM_MENUSELECT,
1560 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1561 ip->fType | ip->fState |
1562 (lppop->wFlags & MF_SYSMENU)), (LPARAM)hmenu);
1565 else if (sendMenuSelect) {
1568 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1569 POPUPMENU *ptm = MENU_GetMenu( topmenu );
1570 MENUITEM *ip = &ptm->items[pos];
1571 SendMessageW( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1572 ip->fType | ip->fState |
1573 (ptm->wFlags & MF_SYSMENU)), (LPARAM)topmenu);
1577 ReleaseDC( lppop->hWnd, hdc );
1581 /***********************************************************************
1582 * MENU_MoveSelection
1584 * Moves currently selected item according to the offset parameter.
1585 * If there is no selection then it should select the last item if
1586 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1588 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1593 TRACE("hwnd=%p hmenu=%p off=0x%04x\n", hwndOwner, hmenu, offset);
1595 menu = MENU_GetMenu( hmenu );
1596 if ((!menu) || (!menu->items)) return;
1598 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1600 if( menu->nItems == 1 ) return; else
1601 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1603 if (!(menu->items[i].fType & MF_SEPARATOR))
1605 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1610 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1611 i >= 0 && i < menu->nItems ; i += offset)
1612 if (!(menu->items[i].fType & MF_SEPARATOR))
1614 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1620 /**********************************************************************
1623 * Set an item's flags, id and text ptr. Called by InsertMenu() and
1626 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id,
1629 LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1631 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1632 TRACE("flags=%x str=%p\n", flags, str);
1634 if (IS_STRING_ITEM(flags))
1638 flags |= MF_SEPARATOR;
1644 /* Item beginning with a backspace is a help item */
1650 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1652 strcpyW( text, str );
1656 else if (IS_BITMAP_ITEM(flags))
1657 item->text = (LPWSTR)HBITMAP_32(LOWORD(str));
1658 else item->text = NULL;
1660 if (flags & MF_OWNERDRAW)
1661 item->dwItemData = (DWORD)str;
1663 item->dwItemData = 0;
1665 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != (HMENU)id) )
1666 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1668 if (flags & MF_POPUP)
1670 POPUPMENU *menu = MENU_GetMenu((HMENU)id);
1671 if (menu) menu->wFlags |= MF_POPUP;
1683 if (flags & MF_POPUP) item->hSubMenu = (HMENU)id;
1685 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1686 flags |= MF_POPUP; /* keep popup */
1688 item->fType = flags & TYPE_MASK;
1689 item->fState = (flags & STATE_MASK) &
1690 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1693 /* Don't call SetRectEmpty here! */
1696 HeapFree( GetProcessHeap(), 0, prevText );
1698 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1703 /**********************************************************************
1706 * Insert (allocate) a new item into a menu.
1708 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1713 if (!(menu = MENU_GetMenu(hMenu)))
1716 /* Find where to insert new item */
1718 if (flags & MF_BYPOSITION) {
1719 if (pos > menu->nItems)
1722 if (!MENU_FindItem( &hMenu, &pos, flags ))
1725 if (!(menu = MENU_GetMenu( hMenu )))
1730 /* Create new items array */
1732 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
1735 WARN("allocation failed\n" );
1738 if (menu->nItems > 0)
1740 /* Copy the old array into the new one */
1741 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1742 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1743 (menu->nItems-pos)*sizeof(MENUITEM) );
1744 HeapFree( GetProcessHeap(), 0, menu->items );
1746 menu->items = newItems;
1748 memset( &newItems[pos], 0, sizeof(*newItems) );
1749 menu->Height = 0; /* force size recalculate */
1750 return &newItems[pos];
1754 /**********************************************************************
1755 * MENU_ParseResource
1757 * Parse a standard menu resource and add items to the menu.
1758 * Return a pointer to the end of the resource.
1760 * NOTE: flags is equivalent to the mtOption field
1762 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1769 flags = GET_WORD(res);
1770 res += sizeof(WORD);
1771 if (!(flags & MF_POPUP))
1774 res += sizeof(WORD);
1777 if (!unicode) res += strlen(str) + 1;
1778 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1779 if (flags & MF_POPUP)
1781 HMENU hSubMenu = CreatePopupMenu();
1782 if (!hSubMenu) return NULL;
1783 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1785 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1786 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1788 else /* Not a popup */
1790 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1791 else AppendMenuW( hMenu, flags, id,
1792 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1794 } while (!(flags & MF_END));
1799 /**********************************************************************
1800 * MENUEX_ParseResource
1802 * Parse an extended menu resource and add items to the menu.
1803 * Return a pointer to the end of the resource.
1805 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1811 mii.cbSize = sizeof(mii);
1812 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1813 mii.fType = GET_DWORD(res);
1814 res += sizeof(DWORD);
1815 mii.fState = GET_DWORD(res);
1816 res += sizeof(DWORD);
1817 mii.wID = GET_DWORD(res);
1818 res += sizeof(DWORD);
1819 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1820 res += sizeof(WORD);
1821 /* Align the text on a word boundary. */
1822 res += (~((int)res - 1)) & 1;
1823 mii.dwTypeData = (LPWSTR) res;
1824 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
1825 /* Align the following fields on a dword boundary. */
1826 res += (~((int)res - 1)) & 3;
1828 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1829 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
1831 if (resinfo & 1) { /* Pop-up? */
1832 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1833 res += sizeof(DWORD);
1834 mii.hSubMenu = CreatePopupMenu();
1837 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
1838 DestroyMenu(mii.hSubMenu);
1841 mii.fMask |= MIIM_SUBMENU;
1842 mii.fType |= MF_POPUP;
1844 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
1846 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
1847 mii.wID, mii.fType);
1848 mii.fType |= MF_SEPARATOR;
1850 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
1851 } while (!(resinfo & MF_END));
1856 /***********************************************************************
1859 * Return the handle of the selected sub-popup menu (if any).
1861 static HMENU MENU_GetSubPopup( HMENU hmenu )
1866 menu = MENU_GetMenu( hmenu );
1868 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
1870 item = &menu->items[menu->FocusedItem];
1871 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
1872 return item->hSubMenu;
1877 /***********************************************************************
1878 * MENU_HideSubPopups
1880 * Hide the sub-popup menus of this menu.
1882 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
1883 BOOL sendMenuSelect )
1885 POPUPMENU *menu = MENU_GetMenu( hmenu );
1887 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
1889 if (menu && top_popup)
1895 if (menu->FocusedItem != NO_SELECTED_ITEM)
1897 item = &menu->items[menu->FocusedItem];
1898 if (!(item->fType & MF_POPUP) ||
1899 !(item->fState & MF_MOUSESELECT)) return;
1900 item->fState &= ~MF_MOUSESELECT;
1901 hsubmenu = item->hSubMenu;
1904 submenu = MENU_GetMenu( hsubmenu );
1905 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
1906 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
1907 DestroyWindow( submenu->hWnd );
1913 /***********************************************************************
1916 * Display the sub-menu of the selected item of this menu.
1917 * Return the handle of the submenu, or hmenu if no submenu to display.
1919 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
1920 BOOL selectFirst, UINT wFlags )
1927 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, selectFirst);
1929 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
1931 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
1933 item = &menu->items[menu->FocusedItem];
1934 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
1937 /* message must be sent before using item,
1938 because nearly everything may be changed by the application ! */
1940 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
1941 if (!(wFlags & TPM_NONOTIFY))
1942 SendMessageW( hwndOwner, WM_INITMENUPOPUP, (WPARAM)item->hSubMenu,
1943 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
1945 item = &menu->items[menu->FocusedItem];
1948 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
1949 if (!(item->fState & MF_HILITE))
1951 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
1952 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1954 SelectObject( hdc, hMenuFont);
1956 item->fState |= MF_HILITE;
1957 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
1958 ReleaseDC( menu->hWnd, hdc );
1960 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
1963 item->fState |= MF_MOUSESELECT;
1965 if (IS_SYSTEM_MENU(menu))
1967 MENU_InitSysMenuPopup(item->hSubMenu,
1968 GetWindowLongW( menu->hWnd, GWL_STYLE ),
1969 GetClassLongW( menu->hWnd, GCL_STYLE));
1971 NC_GetSysPopupPos( menu->hWnd, &rect );
1972 rect.top = rect.bottom;
1973 rect.right = GetSystemMetrics(SM_CXSIZE);
1974 rect.bottom = GetSystemMetrics(SM_CYSIZE);
1978 GetWindowRect( menu->hWnd, &rect );
1979 if (menu->wFlags & MF_POPUP)
1981 rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
1982 rect.top += item->rect.top;
1983 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
1984 rect.bottom = item->rect.top - item->rect.bottom;
1988 rect.left += item->rect.left;
1989 rect.top += item->rect.bottom;
1990 rect.right = item->rect.right - item->rect.left;
1991 rect.bottom = item->rect.bottom - item->rect.top;
1995 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
1996 rect.left, rect.top, rect.right, rect.bottom );
1998 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
1999 return item->hSubMenu;
2004 /**********************************************************************
2007 HWND MENU_IsMenuActive(void)
2012 /***********************************************************************
2015 * Walks menu chain trying to find a menu pt maps to.
2017 static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2019 POPUPMENU *menu = MENU_GetMenu( hMenu );
2020 UINT item = menu->FocusedItem;
2023 /* try subpopup first (if any) */
2024 ret = (item != NO_SELECTED_ITEM &&
2025 (menu->items[item].fType & MF_POPUP) &&
2026 (menu->items[item].fState & MF_MOUSESELECT))
2027 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
2029 if (!ret) /* check the current window (avoiding WM_HITTEST) */
2031 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2032 if( menu->wFlags & MF_POPUP )
2034 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2036 else if (ht == HTSYSMENU)
2037 ret = get_win_sys_menu( menu->hWnd );
2038 else if (ht == HTMENU)
2039 ret = GetMenu( menu->hWnd );
2044 /***********************************************************************
2045 * MENU_ExecFocusedItem
2047 * Execute a menu item (for instance when user pressed Enter).
2048 * Return the wID of the executed item. Otherwise, -1 indicating
2049 * that no menu item was executed;
2050 * Have to receive the flags for the TrackPopupMenu options to avoid
2051 * sending unwanted message.
2054 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2057 POPUPMENU *menu = MENU_GetMenu( hMenu );
2059 TRACE("%p hmenu=%p\n", pmt, hMenu);
2061 if (!menu || !menu->nItems ||
2062 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2064 item = &menu->items[menu->FocusedItem];
2066 TRACE("%p %08x %p\n", hMenu, item->wID, item->hSubMenu);
2068 if (!(item->fType & MF_POPUP))
2070 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2072 /* If TPM_RETURNCMD is set you return the id, but
2073 do not send a message to the owner */
2074 if(!(wFlags & TPM_RETURNCMD))
2076 if( menu->wFlags & MF_SYSMENU )
2077 PostMessageW( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2078 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2080 PostMessageW( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2086 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2091 /***********************************************************************
2092 * MENU_SwitchTracking
2094 * Helper function for menu navigation routines.
2096 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2098 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2099 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2101 TRACE("%p hmenu=%p 0x%04x\n", pmt, hPtMenu, id);
2103 if( pmt->hTopMenu != hPtMenu &&
2104 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2106 /* both are top level menus (system and menu-bar) */
2107 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2108 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2109 pmt->hTopMenu = hPtMenu;
2111 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2112 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2116 /***********************************************************************
2119 * Return TRUE if we can go on with menu tracking.
2121 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2123 TRACE("%p hPtMenu=%p\n", pmt, hPtMenu);
2128 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2131 if( IS_SYSTEM_MENU(ptmenu) )
2132 item = ptmenu->items;
2134 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2138 if( ptmenu->FocusedItem != id )
2139 MENU_SwitchTracking( pmt, hPtMenu, id );
2141 /* If the popup menu is not already "popped" */
2142 if(!(item->fState & MF_MOUSESELECT ))
2144 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2149 /* Else the click was on the menu bar, finish the tracking */
2154 /***********************************************************************
2157 * Return the value of MENU_ExecFocusedItem if
2158 * the selected item was not a popup. Else open the popup.
2159 * A -1 return value indicates that we go on with menu tracking.
2162 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2164 TRACE("%p hmenu=%p\n", pmt, hPtMenu);
2169 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2172 if( IS_SYSTEM_MENU(ptmenu) )
2173 item = ptmenu->items;
2175 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2177 if( item && (ptmenu->FocusedItem == id ))
2179 if( !(item->fType & MF_POPUP) )
2180 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2182 /* If we are dealing with the top-level menu */
2183 /* and this is a click on an already "popped" item: */
2184 /* Stop the menu tracking and close the opened submenus */
2185 if((pmt->hTopMenu == hPtMenu) && ptmenu->bTimeToHide)
2188 ptmenu->bTimeToHide = TRUE;
2194 /***********************************************************************
2197 * Return TRUE if we can go on with menu tracking.
2199 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2201 UINT id = NO_SELECTED_ITEM;
2202 POPUPMENU *ptmenu = NULL;
2206 ptmenu = MENU_GetMenu( hPtMenu );
2207 if( IS_SYSTEM_MENU(ptmenu) )
2210 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2213 if( id == NO_SELECTED_ITEM )
2215 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2216 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2219 else if( ptmenu->FocusedItem != id )
2221 MENU_SwitchTracking( pmt, hPtMenu, id );
2222 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2228 /***********************************************************************
2231 static void MENU_SetCapture( HWND hwnd )
2235 SERVER_START_REQ( set_capture_window )
2238 req->flags = CAPTURE_MENU;
2239 if (!wine_server_call_err( req ))
2241 previous = reply->previous;
2242 hwnd = reply->full_handle;
2247 if (previous && previous != hwnd)
2248 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
2252 /***********************************************************************
2255 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2257 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2259 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2261 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2262 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2264 MDINEXTMENU next_menu;
2269 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2270 next_menu.hmenuNext = 0;
2271 next_menu.hwndNext = 0;
2272 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2274 TRACE("%p [%p] -> %p [%p]\n",
2275 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2277 if (!next_menu.hmenuNext || !next_menu.hwndNext)
2279 DWORD style = GetWindowLongW( pmt->hOwnerWnd, GWL_STYLE );
2280 hNewWnd = pmt->hOwnerWnd;
2281 if( IS_SYSTEM_MENU(menu) )
2283 /* switch to the menu bar */
2285 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2289 menu = MENU_GetMenu( hNewMenu );
2290 id = menu->nItems - 1;
2293 else if (style & WS_SYSMENU )
2295 /* switch to the system menu */
2296 hNewMenu = get_win_sys_menu( hNewWnd );
2300 else /* application returned a new menu to switch to */
2302 hNewMenu = next_menu.hmenuNext;
2303 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2305 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2307 DWORD style = GetWindowLongW( hNewWnd, GWL_STYLE );
2309 if (style & WS_SYSMENU &&
2310 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2312 /* get the real system menu */
2313 hNewMenu = get_win_sys_menu(hNewWnd);
2315 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2317 /* FIXME: Not sure what to do here;
2318 * perhaps try to track hNewMenu as a popup? */
2320 TRACE(" -- got confused.\n");
2327 if( hNewMenu != pmt->hTopMenu )
2329 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2331 if( pmt->hCurrentMenu != pmt->hTopMenu )
2332 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2335 if( hNewWnd != pmt->hOwnerWnd )
2337 pmt->hOwnerWnd = hNewWnd;
2338 MENU_SetCapture( pmt->hOwnerWnd );
2341 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2342 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2349 /***********************************************************************
2352 * The idea is not to show the popup if the next input message is
2353 * going to hide it anyway.
2355 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2359 msg.hwnd = pmt->hOwnerWnd;
2361 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2362 pmt->trackFlags |= TF_SKIPREMOVE;
2367 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2368 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2370 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2371 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2372 if( msg.message == WM_KEYDOWN &&
2373 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2375 pmt->trackFlags |= TF_SUSPENDPOPUP;
2382 /* failures go through this */
2383 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2387 /***********************************************************************
2390 * Handle a VK_ESCAPE key event in a menu.
2392 static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2394 BOOL bEndMenu = TRUE;
2396 if (pmt->hCurrentMenu != pmt->hTopMenu)
2398 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2400 if (menu->wFlags & MF_POPUP)
2402 HMENU hmenutmp, hmenuprev;
2404 hmenuprev = hmenutmp = pmt->hTopMenu;
2406 /* close topmost popup */
2407 while (hmenutmp != pmt->hCurrentMenu)
2409 hmenuprev = hmenutmp;
2410 hmenutmp = MENU_GetSubPopup( hmenuprev );
2413 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2414 pmt->hCurrentMenu = hmenuprev;
2422 /***********************************************************************
2425 * Handle a VK_LEFT key event in a menu.
2427 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2430 HMENU hmenutmp, hmenuprev;
2433 hmenuprev = hmenutmp = pmt->hTopMenu;
2434 menu = MENU_GetMenu( hmenutmp );
2436 /* Try to move 1 column left (if possible) */
2437 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2438 NO_SELECTED_ITEM ) {
2440 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2445 /* close topmost popup */
2446 while (hmenutmp != pmt->hCurrentMenu)
2448 hmenuprev = hmenutmp;
2449 hmenutmp = MENU_GetSubPopup( hmenuprev );
2452 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2453 pmt->hCurrentMenu = hmenuprev;
2455 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2457 /* move menu bar selection if no more popups are left */
2459 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2460 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2462 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2464 /* A sublevel menu was displayed - display the next one
2465 * unless there is another displacement coming up */
2467 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2468 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2469 pmt->hTopMenu, TRUE, wFlags);
2475 /***********************************************************************
2478 * Handle a VK_RIGHT key event in a menu.
2480 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2483 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2486 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2488 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->items[0].text),
2489 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2491 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2493 /* If already displaying a popup, try to display sub-popup */
2495 hmenutmp = pmt->hCurrentMenu;
2496 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2498 /* if subpopup was displayed then we are done */
2499 if (hmenutmp != pmt->hCurrentMenu) return;
2502 /* Check to see if there's another column */
2503 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2504 NO_SELECTED_ITEM ) {
2505 TRACE("Going to %d.\n", nextcol );
2506 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2511 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2513 if( pmt->hCurrentMenu != pmt->hTopMenu )
2515 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2516 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2517 } else hmenutmp = 0;
2519 /* try to move to the next item */
2520 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2521 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2523 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2524 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2525 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2526 pmt->hTopMenu, TRUE, wFlags);
2530 /***********************************************************************
2533 * Menu tracking code.
2535 static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2536 HWND hwnd, const RECT *lprect )
2541 INT executedMenuId = -1;
2543 BOOL enterIdleSent = FALSE;
2546 mt.hCurrentMenu = hmenu;
2547 mt.hTopMenu = hmenu;
2548 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2552 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p (%ld,%ld)-(%ld,%ld)\n",
2553 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2554 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2557 if (!(menu = MENU_GetMenu( hmenu )))
2559 WARN("Invalid menu handle %p\n", hmenu);
2560 SetLastError(ERROR_INVALID_MENU_HANDLE);
2564 if (wFlags & TPM_BUTTONDOWN)
2566 /* Get the result in order to start the tracking or not */
2567 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2568 fEndMenu = !fRemove;
2571 if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
2573 MENU_SetCapture( mt.hOwnerWnd );
2577 menu = MENU_GetMenu( mt.hCurrentMenu );
2578 if (!menu) /* sometimes happens if I do a window manager close */
2581 /* we have to keep the message in the queue until it's
2582 * clear that menu loop is not over yet. */
2586 if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
2588 if (!CallMsgFilterW( &msg, MSGF_MENU )) break;
2589 /* remove the message from the queue */
2590 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2596 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2597 enterIdleSent = TRUE;
2598 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2604 /* check if EndMenu() tried to cancel us, by posting this message */
2605 if(msg.message == WM_CANCELMODE)
2607 /* we are now out of the loop */
2610 /* remove the message from the queue */
2611 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2613 /* break out of internal loop, ala ESCAPE */
2617 TranslateMessage( &msg );
2620 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2621 enterIdleSent=FALSE;
2624 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2627 * Use the mouse coordinates in lParam instead of those in the MSG
2628 * struct to properly handle synthetic messages. They are already
2629 * in screen coordinates.
2631 mt.pt.x = (short)LOWORD(msg.lParam);
2632 mt.pt.y = (short)HIWORD(msg.lParam);
2634 /* Find a menu for this mouse event */
2635 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2639 /* no WM_NC... messages in captured state */
2641 case WM_RBUTTONDBLCLK:
2642 case WM_RBUTTONDOWN:
2643 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2645 case WM_LBUTTONDBLCLK:
2646 case WM_LBUTTONDOWN:
2647 /* If the message belongs to the menu, removes it from the queue */
2648 /* Else, end menu tracking */
2649 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2650 fEndMenu = !fRemove;
2654 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2657 /* Check if a menu was selected by the mouse */
2660 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2662 /* End the loop if executedMenuId is an item ID */
2663 /* or if the job was done (executedMenuId = 0). */
2664 fEndMenu = fRemove = (executedMenuId != -1);
2666 /* No menu was selected by the mouse */
2667 /* if the function was called by TrackPopupMenu, continue
2668 with the menu tracking. If not, stop it */
2670 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2675 /* the selected menu item must be changed every time */
2676 /* the mouse moves. */
2679 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2681 } /* switch(msg.message) - mouse */
2683 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2685 fRemove = TRUE; /* Keyboard messages are always removed */
2698 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2699 NO_SELECTED_ITEM, FALSE, 0 );
2702 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2703 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2706 case VK_DOWN: /* If on menu bar, pull-down the menu */
2708 menu = MENU_GetMenu( mt.hCurrentMenu );
2709 if (!(menu->wFlags & MF_POPUP))
2710 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2711 else /* otherwise try to move selection */
2712 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2716 MENU_KeyLeft( &mt, wFlags );
2720 MENU_KeyRight( &mt, wFlags );
2724 fEndMenu = MENU_KeyEscape(&mt, wFlags);
2730 hi.cbSize = sizeof(HELPINFO);
2731 hi.iContextType = HELPINFO_MENUITEM;
2732 if (menu->FocusedItem == NO_SELECTED_ITEM)
2735 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2736 hi.hItemHandle = hmenu;
2737 hi.dwContextId = menu->dwContextHelpID;
2738 hi.MousePos = msg.pt;
2739 SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
2746 break; /* WM_KEYDOWN */
2753 if (msg.wParam == '\r' || msg.wParam == ' ')
2755 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2756 fEndMenu = (executedMenuId != -1);
2761 /* Hack to avoid control chars. */
2762 /* We will find a better way real soon... */
2763 if (msg.wParam < 32) break;
2765 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
2766 LOWORD(msg.wParam), FALSE );
2767 if (pos == (UINT)-2) fEndMenu = TRUE;
2768 else if (pos == (UINT)-1) MessageBeep(0);
2771 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2773 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2774 fEndMenu = (executedMenuId != -1);
2778 } /* switch(msg.message) - kbd */
2782 DispatchMessageW( &msg );
2785 if (!fEndMenu) fRemove = TRUE;
2787 /* finally remove message from the queue */
2789 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2790 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2791 else mt.trackFlags &= ~TF_SKIPREMOVE;
2794 MENU_SetCapture(0); /* release the capture */
2796 /* If dropdown is still painted and the close box is clicked on
2797 then the menu will be destroyed as part of the DispatchMessage above.
2798 This will then invalidate the menu handle in mt.hTopMenu. We should
2799 check for this first. */
2800 if( IsMenu( mt.hTopMenu ) )
2802 menu = MENU_GetMenu( mt.hTopMenu );
2804 if( IsWindow( mt.hOwnerWnd ) )
2806 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2808 if (menu && (menu->wFlags & MF_POPUP))
2810 DestroyWindow( menu->hWnd );
2813 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2814 SendMessageW( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2817 /* Reset the variable for hiding menu */
2818 if( menu ) menu->bTimeToHide = FALSE;
2821 /* The return value is only used by TrackPopupMenu */
2822 if (!(wFlags & TPM_RETURNCMD)) return TRUE;
2823 if (executedMenuId == -1) executedMenuId = 0;
2824 return executedMenuId;
2827 /***********************************************************************
2830 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
2834 TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
2838 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2839 if (!(wFlags & TPM_NONOTIFY))
2840 SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2842 SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
2844 if (!(wFlags & TPM_NONOTIFY))
2846 SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
2847 /* If an app changed/recreated menu bar entries in WM_INITMENU
2848 * menu sizes will be recalculated once the menu created/shown.
2852 /* This makes the menus of applications built with Delphi work.
2853 * It also enables menus to be displayed in more than one window,
2854 * but there are some bugs left that need to be fixed in this case.
2856 if ((menu = MENU_GetMenu( hMenu ))) menu->hWnd = hWnd;
2860 /***********************************************************************
2863 static BOOL MENU_ExitTracking(HWND hWnd)
2865 TRACE("hwnd=%p\n", hWnd);
2867 SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 );
2873 /***********************************************************************
2874 * MENU_TrackMouseMenuBar
2876 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2878 void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
2880 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
2881 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2883 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
2887 /* map point to parent client coordinates */
2888 HWND parent = GetAncestor( hWnd, GA_PARENT );
2889 if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );
2891 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2892 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
2893 MENU_ExitTracking(hWnd);
2898 /***********************************************************************
2899 * MENU_TrackKbdMenuBar
2901 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2903 void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar)
2905 UINT uItem = NO_SELECTED_ITEM;
2907 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2909 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
2911 /* find window that has a menu */
2913 while (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)
2914 if (!(hwnd = GetParent( hwnd ))) return;
2916 /* check if we have to track a system menu */
2918 hTrackMenu = GetMenu( hwnd );
2919 if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' )
2921 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
2922 hTrackMenu = get_win_sys_menu( hwnd );
2924 wParam |= HTSYSMENU; /* prevent item lookup */
2927 if (!IsMenu( hTrackMenu )) return;
2929 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
2931 if( wChar && wChar != ' ' )
2933 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) );
2934 if ( uItem >= (UINT)(-2) )
2936 if( uItem == (UINT)(-1) ) MessageBeep(0);
2937 /* schedule end of menu tracking */
2938 wFlags |= TF_ENDMENU;
2943 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
2945 if (wParam & HTSYSMENU)
2947 /* prevent sysmenu activation for managed windows on Alt down/up */
2948 if (GetPropA( hwnd, "__wine_x11_managed" ))
2949 wFlags |= TF_ENDMENU; /* schedule end of menu tracking */
2953 if( uItem == NO_SELECTED_ITEM )
2954 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
2956 PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
2960 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
2961 MENU_ExitTracking( hwnd );
2965 /**********************************************************************
2966 * TrackPopupMenu (USER32.@)
2968 * Like the win32 API, the function return the command ID only if the
2969 * flag TPM_RETURNCMD is on.
2972 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
2973 INT nReserved, HWND hWnd, const RECT *lpRect )
2977 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
2979 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2980 if (!(wFlags & TPM_NONOTIFY))
2981 SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0);
2983 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
2984 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
2985 MENU_ExitTracking(hWnd);
2990 /**********************************************************************
2991 * TrackPopupMenuEx (USER32.@)
2993 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
2994 HWND hWnd, LPTPMPARAMS lpTpm )
2996 FIXME("not fully implemented\n" );
2997 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
2998 lpTpm ? &lpTpm->rcExclude : NULL );
3001 /***********************************************************************
3004 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3006 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3008 TRACE("hwnd=%p msg=0x%04x wp=0x%04x lp=0x%08lx\n", hwnd, message, wParam, lParam);
3014 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3015 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3019 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3020 return MA_NOACTIVATE;
3025 BeginPaint( hwnd, &ps );
3026 MENU_DrawPopupMenu( hwnd, ps.hdc,
3027 (HMENU)GetWindowLongW( hwnd, 0 ) );
3028 EndPaint( hwnd, &ps );
3035 /* zero out global pointer in case resident popup window was destroyed. */
3036 if (hwnd == top_popup) top_popup = 0;
3043 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
3046 SetWindowLongW( hwnd, 0, 0 );
3049 case MM_SETMENUHANDLE:
3050 SetWindowLongW( hwnd, 0, wParam );
3053 case MM_GETMENUHANDLE:
3054 return GetWindowLongW( hwnd, 0 );
3057 return DefWindowProcW( hwnd, message, wParam, lParam );
3063 /***********************************************************************
3064 * MENU_GetMenuBarHeight
3066 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3068 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3069 INT orgX, INT orgY )
3075 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
3077 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3079 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3080 SelectObject( hdc, hMenuFont);
3081 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3082 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3083 ReleaseDC( hwnd, hdc );
3084 return lppop->Height;
3088 /*******************************************************************
3089 * ChangeMenuA (USER32.@)
3091 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3092 UINT id, UINT flags )
3094 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3095 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3097 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3098 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3100 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3101 flags & MF_BYPOSITION ? pos : id,
3102 flags & ~MF_REMOVE );
3103 /* Default: MF_INSERT */
3104 return InsertMenuA( hMenu, pos, flags, id, data );
3108 /*******************************************************************
3109 * ChangeMenuW (USER32.@)
3111 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3112 UINT id, UINT flags )
3114 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3115 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3117 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3118 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3120 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3121 flags & MF_BYPOSITION ? pos : id,
3122 flags & ~MF_REMOVE );
3123 /* Default: MF_INSERT */
3124 return InsertMenuW( hMenu, pos, flags, id, data );
3128 /*******************************************************************
3129 * CheckMenuItem (USER32.@)
3131 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3136 TRACE("menu=%p id=%04x flags=%04x\n", hMenu, id, flags );
3137 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3138 ret = item->fState & MF_CHECKED;
3139 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3140 else item->fState &= ~MF_CHECKED;
3145 /**********************************************************************
3146 * EnableMenuItem (USER32.@)
3148 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3154 TRACE("(%p, %04x, %04x) !\n", hMenu, wItemID, wFlags);
3156 /* Get the Popupmenu to access the owner menu */
3157 if (!(menu = MENU_GetMenu(hMenu)))
3160 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3163 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3164 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3166 /* If the close item in the system menu change update the close button */
3167 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3169 if (menu->hSysMenuOwner != 0)
3171 POPUPMENU* parentMenu;
3173 /* Get the parent menu to access*/
3174 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3177 /* Refresh the frame to reflect the change*/
3178 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3179 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3187 /*******************************************************************
3188 * GetMenuStringA (USER32.@)
3190 INT WINAPI GetMenuStringA(
3191 HMENU hMenu, /* [in] menuhandle */
3192 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3193 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3194 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3195 UINT wFlags /* [in] MF_ flags */
3199 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3200 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3201 if (!IS_STRING_ITEM(item->fType)) return 0;
3202 if (!str || !nMaxSiz) return strlenW(item->text);
3204 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3206 TRACE("returning '%s'\n", str );
3211 /*******************************************************************
3212 * GetMenuStringW (USER32.@)
3214 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3215 LPWSTR str, INT nMaxSiz, UINT wFlags )
3219 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3220 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3221 if (!IS_STRING_ITEM(item->fType)) return 0;
3222 if (!str || !nMaxSiz) return strlenW(item->text);
3224 lstrcpynW( str, item->text, nMaxSiz );
3225 return strlenW(str);
3229 /**********************************************************************
3230 * HiliteMenuItem (USER32.@)
3232 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3236 TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
3237 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3238 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3239 if (menu->FocusedItem == wItemID) return TRUE;
3240 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3241 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3246 /**********************************************************************
3247 * GetMenuState (USER32.@)
3249 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3252 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, wItemID, wFlags);
3253 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3254 debug_print_menuitem (" item: ", item, "");
3255 if (item->fType & MF_POPUP)
3257 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3258 if (!menu) return -1;
3259 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3263 /* We used to (from way back then) mask the result to 0xff. */
3264 /* I don't know why and it seems wrong as the documented */
3265 /* return flag MF_SEPARATOR is outside that mask. */
3266 return (item->fType | item->fState);
3271 /**********************************************************************
3272 * GetMenuItemCount (USER32.@)
3274 INT WINAPI GetMenuItemCount( HMENU hMenu )
3276 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3277 if (!menu) return -1;
3278 TRACE("(%p) returning %d\n", hMenu, menu->nItems );
3279 return menu->nItems;
3283 /**********************************************************************
3284 * GetMenuItemID (USER32.@)
3286 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3290 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
3291 if (lpmi->fType & MF_POPUP) return -1;
3297 /*******************************************************************
3298 * InsertMenuW (USER32.@)
3300 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3301 UINT_PTR id, LPCWSTR str )
3305 if (IS_STRING_ITEM(flags) && str)
3306 TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3307 hMenu, pos, flags, id, debugstr_w(str) );
3308 else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %08lx (not a string)\n",
3309 hMenu, pos, flags, id, (DWORD)str );
3311 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3313 if (!(MENU_SetItemData( item, flags, id, str )))
3315 RemoveMenu( hMenu, pos, flags );
3319 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3320 (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
3322 item->hCheckBit = item->hUnCheckBit = 0;
3327 /*******************************************************************
3328 * InsertMenuA (USER32.@)
3330 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3331 UINT_PTR id, LPCSTR str )
3335 if (IS_STRING_ITEM(flags) && str)
3337 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3338 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3341 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3342 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3343 HeapFree( GetProcessHeap(), 0, newstr );
3347 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3351 /*******************************************************************
3352 * AppendMenuA (USER32.@)
3354 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3355 UINT_PTR id, LPCSTR data )
3357 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3361 /*******************************************************************
3362 * AppendMenuW (USER32.@)
3364 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3365 UINT_PTR id, LPCWSTR data )
3367 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3371 /**********************************************************************
3372 * RemoveMenu (USER32.@)
3374 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3379 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3380 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3381 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3385 MENU_FreeItemData( item );
3387 if (--menu->nItems == 0)
3389 HeapFree( GetProcessHeap(), 0, menu->items );
3394 while(nPos < menu->nItems)
3400 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3401 menu->nItems * sizeof(MENUITEM) );
3407 /**********************************************************************
3408 * DeleteMenu (USER32.@)
3410 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3412 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3413 if (!item) return FALSE;
3414 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3415 /* nPos is now the position of the item */
3416 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3421 /*******************************************************************
3422 * ModifyMenuW (USER32.@)
3424 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3425 UINT_PTR id, LPCWSTR str )
3429 if (IS_STRING_ITEM(flags))
3431 TRACE("%p %d %04x %04x %s\n", hMenu, pos, flags, id, debugstr_w(str) );
3435 TRACE("%p %d %04x %04x %08lx\n", hMenu, pos, flags, id, (DWORD)str );
3438 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3439 return MENU_SetItemData( item, flags, id, str );
3443 /*******************************************************************
3444 * ModifyMenuA (USER32.@)
3446 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3447 UINT_PTR id, LPCSTR str )
3451 if (IS_STRING_ITEM(flags) && str)
3453 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3454 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3457 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3458 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3459 HeapFree( GetProcessHeap(), 0, newstr );
3463 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3467 /**********************************************************************
3468 * CreatePopupMenu (USER32.@)
3470 HMENU WINAPI CreatePopupMenu(void)
3475 if (!(hmenu = CreateMenu())) return 0;
3476 menu = MENU_GetMenu( hmenu );
3477 menu->wFlags |= MF_POPUP;
3478 menu->bTimeToHide = FALSE;
3483 /**********************************************************************
3484 * GetMenuCheckMarkDimensions (USER.417)
3485 * GetMenuCheckMarkDimensions (USER32.@)
3487 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3489 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3493 /**********************************************************************
3494 * SetMenuItemBitmaps (USER32.@)
3496 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3497 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3500 TRACE("(%p, %04x, %04x, %p, %p)\n",
3501 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3502 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3504 if (!hNewCheck && !hNewUnCheck)
3506 item->fState &= ~MF_USECHECKBITMAPS;
3508 else /* Install new bitmaps */
3510 item->hCheckBit = hNewCheck;
3511 item->hUnCheckBit = hNewUnCheck;
3512 item->fState |= MF_USECHECKBITMAPS;
3518 /**********************************************************************
3519 * CreateMenu (USER32.@)
3521 HMENU WINAPI CreateMenu(void)
3525 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3526 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3528 ZeroMemory(menu, sizeof(POPUPMENU));
3529 menu->wMagic = MENU_MAGIC;
3530 menu->FocusedItem = NO_SELECTED_ITEM;
3531 menu->bTimeToHide = FALSE;
3533 TRACE("return %p\n", hMenu );
3539 /**********************************************************************
3540 * DestroyMenu (USER32.@)
3542 BOOL WINAPI DestroyMenu( HMENU hMenu )
3544 TRACE("(%p)\n", hMenu);
3546 /* Silently ignore attempts to destroy default system popup */
3548 if (hMenu && hMenu != MENU_DefSysPopup)
3550 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3552 if (!lppop) return FALSE;
3554 lppop->wMagic = 0; /* Mark it as destroyed */
3556 /* DestroyMenu should not destroy system menu popup owner */
3557 if ((lppop->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && lppop->hWnd)
3559 DestroyWindow( lppop->hWnd );
3563 if (lppop->items) /* recursively destroy submenus */
3566 MENUITEM *item = lppop->items;
3567 for (i = lppop->nItems; i > 0; i--, item++)
3569 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3570 MENU_FreeItemData( item );
3572 HeapFree( GetProcessHeap(), 0, lppop->items );
3574 USER_HEAP_FREE( hMenu );
3576 return (hMenu != MENU_DefSysPopup);
3580 /**********************************************************************
3581 * GetSystemMenu (USER32.@)
3583 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3585 WND *wndPtr = WIN_GetPtr( hWnd );
3588 if (wndPtr == WND_OTHER_PROCESS)
3590 if (IsWindow( hWnd )) FIXME( "not supported on other process window %p\n", hWnd );
3594 if( wndPtr->hSysMenu )
3598 DestroyMenu(wndPtr->hSysMenu);
3599 wndPtr->hSysMenu = 0;
3603 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3606 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3607 menu->items[0].hSubMenu = MENU_CopySysPopup();
3611 WARN("Current sys-menu (%p) of wnd %p is broken\n",
3612 wndPtr->hSysMenu, hWnd);
3613 wndPtr->hSysMenu = 0;
3618 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3619 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3621 if( wndPtr->hSysMenu )
3624 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3626 /* Store the dummy sysmenu handle to facilitate the refresh */
3627 /* of the close button if the SC_CLOSE item change */
3628 menu = MENU_GetMenu(retvalue);
3630 menu->hSysMenuOwner = wndPtr->hSysMenu;
3632 WIN_ReleasePtr( wndPtr );
3634 return bRevert ? 0 : retvalue;
3638 /*******************************************************************
3639 * SetSystemMenu (USER32.@)
3641 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3643 WND *wndPtr = WIN_GetPtr( hwnd );
3645 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
3647 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3648 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3649 WIN_ReleasePtr( wndPtr );
3656 /**********************************************************************
3657 * GetMenu (USER32.@)
3659 HMENU WINAPI GetMenu( HWND hWnd )
3661 HMENU retvalue = (HMENU)GetWindowLongPtrW( hWnd, GWLP_ID );
3662 TRACE("for %p returning %p\n", hWnd, retvalue);
3667 /**********************************************************************
3670 * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
3671 * SetWindowPos call that would result if SetMenu were called directly.
3673 BOOL MENU_SetMenu( HWND hWnd, HMENU hMenu )
3675 TRACE("(%p, %p);\n", hWnd, hMenu);
3677 if (hMenu && !IsMenu(hMenu))
3679 WARN("hMenu %p is not a menu handle\n", hMenu);
3682 if (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
3684 hWnd = WIN_GetFullHandle( hWnd );
3685 if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */
3691 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
3693 lpmenu->hWnd = hWnd;
3694 lpmenu->Height = 0; /* Make sure we recalculate the size */
3696 SetWindowLongPtrW( hWnd, GWLP_ID, (LONG_PTR)hMenu );
3701 /**********************************************************************
3702 * SetMenu (USER32.@)
3704 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
3706 if(!MENU_SetMenu(hWnd, hMenu))
3709 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3710 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3715 /**********************************************************************
3716 * GetSubMenu (USER32.@)
3718 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
3722 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3723 if (!(lpmi->fType & MF_POPUP)) return 0;
3724 return lpmi->hSubMenu;
3728 /**********************************************************************
3729 * DrawMenuBar (USER32.@)
3731 BOOL WINAPI DrawMenuBar( HWND hWnd )
3734 HMENU hMenu = GetMenu(hWnd);
3736 if (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
3737 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
3739 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
3740 lppop->hwndOwner = hWnd;
3741 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3742 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3746 /***********************************************************************
3747 * DrawMenuBarTemp (USER32.@)
3751 * called by W98SE desk.cpl Control Panel Applet
3753 * Not 100% sure about the param names, but close.
3755 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont)
3762 hMenu = GetMenu(hwnd);
3767 lppop = MENU_GetMenu( hMenu );
3768 if (lppop == NULL || lprect == NULL)
3770 retvalue = GetSystemMetrics(SM_CYMENU);
3774 TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont);
3776 hfontOld = SelectObject( hDC, hFont);
3778 if (lppop->Height == 0)
3779 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
3781 lprect->bottom = lprect->top + lppop->Height;
3783 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
3785 SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE));
3786 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
3787 LineTo( hDC, lprect->right, lprect->bottom );
3789 if (lppop->nItems == 0)
3791 retvalue = GetSystemMetrics(SM_CYMENU);
3795 for (i = 0; i < lppop->nItems; i++)
3797 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
3798 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
3800 retvalue = lppop->Height;
3803 if (hfontOld) SelectObject (hDC, hfontOld);
3807 /***********************************************************************
3808 * EndMenu (USER.187)
3809 * EndMenu (USER32.@)
3811 void WINAPI EndMenu(void)
3813 /* if we are in the menu code, and it is active */
3814 if (!fEndMenu && top_popup)
3816 /* terminate the menu handling code */
3819 /* needs to be posted to wakeup the internal menu handler */
3820 /* which will now terminate the menu, in the event that */
3821 /* the main window was minimized, or lost focus, so we */
3822 /* don't end up with an orphaned menu */
3823 PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
3828 /***********************************************************************
3829 * LookupMenuHandle (USER.217)
3831 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
3833 HMENU hmenu32 = HMENU_32(hmenu);
3835 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
3836 else return HMENU_16(hmenu32);
3840 /**********************************************************************
3841 * LoadMenu (USER.150)
3843 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
3849 if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
3850 if (!name) return 0;
3852 instance = GetExePtr( instance );
3853 if (!(hRsrc = FindResource16( instance, name, (LPSTR)RT_MENU ))) return 0;
3854 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
3855 hMenu = LoadMenuIndirect16(LockResource16(handle));
3856 FreeResource16( handle );
3861 /*****************************************************************
3862 * LoadMenuA (USER32.@)
3864 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
3866 HRSRC hrsrc = FindResourceA( instance, name, (LPSTR)RT_MENU );
3867 if (!hrsrc) return 0;
3868 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
3872 /*****************************************************************
3873 * LoadMenuW (USER32.@)
3875 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
3877 HRSRC hrsrc = FindResourceW( instance, name, (LPWSTR)RT_MENU );
3878 if (!hrsrc) return 0;
3879 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
3883 /**********************************************************************
3884 * LoadMenuIndirect (USER.220)
3886 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
3889 WORD version, offset;
3890 LPCSTR p = (LPCSTR)template;
3892 TRACE("(%p)\n", template );
3893 version = GET_WORD(p);
3897 WARN("version must be 0 for Win16\n" );
3900 offset = GET_WORD(p);
3901 p += sizeof(WORD) + offset;
3902 if (!(hMenu = CreateMenu())) return 0;
3903 if (!MENU_ParseResource( p, hMenu, FALSE ))
3905 DestroyMenu( hMenu );
3908 return HMENU_16(hMenu);
3912 /**********************************************************************
3913 * LoadMenuIndirectW (USER32.@)
3915 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
3918 WORD version, offset;
3919 LPCSTR p = (LPCSTR)template;
3921 version = GET_WORD(p);
3923 TRACE("%p, ver %d\n", template, version );
3926 case 0: /* standard format is version of 0 */
3927 offset = GET_WORD(p);
3928 p += sizeof(WORD) + offset;
3929 if (!(hMenu = CreateMenu())) return 0;
3930 if (!MENU_ParseResource( p, hMenu, TRUE ))
3932 DestroyMenu( hMenu );
3936 case 1: /* extended format is version of 1 */
3937 offset = GET_WORD(p);
3938 p += sizeof(WORD) + offset;
3939 if (!(hMenu = CreateMenu())) return 0;
3940 if (!MENUEX_ParseResource( p, hMenu))
3942 DestroyMenu( hMenu );
3947 ERR("version %d not supported.\n", version);
3953 /**********************************************************************
3954 * LoadMenuIndirectA (USER32.@)
3956 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
3958 return LoadMenuIndirectW( template );
3962 /**********************************************************************
3965 BOOL WINAPI IsMenu(HMENU hmenu)
3967 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
3968 return menu != NULL;
3971 /**********************************************************************
3972 * GetMenuItemInfo_common
3975 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
3976 LPMENUITEMINFOW lpmii, BOOL unicode)
3978 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
3980 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
3985 if (lpmii->fMask & MIIM_TYPE) {
3986 lpmii->fType = menu->fType;
3987 switch (MENU_ITEM_TYPE(menu->fType)) {
3989 break; /* will be done below */
3992 lpmii->dwTypeData = menu->text;
3999 /* copy the text string */
4000 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4001 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4006 len = strlenW(menu->text);
4007 if(lpmii->dwTypeData && lpmii->cch)
4008 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4012 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4013 if(lpmii->dwTypeData && lpmii->cch)
4014 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4015 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4016 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4018 /* if we've copied a substring we return its length */
4019 if(lpmii->dwTypeData && lpmii->cch)
4021 if (lpmii->cch <= len) lpmii->cch--;
4023 else /* return length of string */
4027 if (lpmii->fMask & MIIM_FTYPE)
4028 lpmii->fType = menu->fType;
4030 if (lpmii->fMask & MIIM_BITMAP)
4031 lpmii->hbmpItem = menu->hbmpItem;
4033 if (lpmii->fMask & MIIM_STATE)
4034 lpmii->fState = menu->fState;
4036 if (lpmii->fMask & MIIM_ID)
4037 lpmii->wID = menu->wID;
4039 if (lpmii->fMask & MIIM_SUBMENU)
4040 lpmii->hSubMenu = menu->hSubMenu;
4042 if (lpmii->fMask & MIIM_CHECKMARKS) {
4043 lpmii->hbmpChecked = menu->hCheckBit;
4044 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4046 if (lpmii->fMask & MIIM_DATA)
4047 lpmii->dwItemData = menu->dwItemData;
4052 /**********************************************************************
4053 * GetMenuItemInfoA (USER32.@)
4055 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4056 LPMENUITEMINFOA lpmii)
4058 return GetMenuItemInfo_common (hmenu, item, bypos,
4059 (LPMENUITEMINFOW)lpmii, FALSE);
4062 /**********************************************************************
4063 * GetMenuItemInfoW (USER32.@)
4065 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4066 LPMENUITEMINFOW lpmii)
4068 return GetMenuItemInfo_common (hmenu, item, bypos,
4073 /* set a menu item text from a ASCII or Unicode string */
4074 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4079 menu->fType |= MF_SEPARATOR;
4083 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4084 strcpyW( menu->text, text );
4088 LPCSTR str = (LPCSTR)text;
4089 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4090 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4091 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4096 /**********************************************************************
4097 * SetMenuItemInfo_common
4100 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4101 const MENUITEMINFOW *lpmii,
4104 if (!menu) return FALSE;
4106 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4108 if (lpmii->fMask & MIIM_TYPE ) {
4109 /* Get rid of old string. */
4110 if (IS_STRING_ITEM(menu->fType) && menu->text) {
4111 HeapFree(GetProcessHeap(), 0, menu->text);
4115 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4116 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4117 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4119 menu->text = lpmii->dwTypeData;
4121 if (IS_STRING_ITEM(menu->fType))
4122 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4125 if (lpmii->fMask & MIIM_FTYPE ) {
4126 /* free the string when the type is changing */
4127 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4128 HeapFree(GetProcessHeap(), 0, menu->text);
4131 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4132 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4133 if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4134 menu->fType |= MF_SEPARATOR;
4137 if (lpmii->fMask & MIIM_STRING ) {
4138 if (IS_STRING_ITEM(menu->fType)) {
4139 /* free the string when used */
4140 HeapFree(GetProcessHeap(), 0, menu->text);
4141 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4145 if (lpmii->fMask & MIIM_STATE)
4147 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4148 menu->fState = lpmii->fState;
4151 if (lpmii->fMask & MIIM_ID)
4152 menu->wID = lpmii->wID;
4154 if (lpmii->fMask & MIIM_SUBMENU) {
4155 menu->hSubMenu = lpmii->hSubMenu;
4156 if (menu->hSubMenu) {
4157 POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
4159 subMenu->wFlags |= MF_POPUP;
4160 menu->fType |= MF_POPUP;
4163 /* FIXME: Return an error ? */
4164 menu->fType &= ~MF_POPUP;
4167 menu->fType &= ~MF_POPUP;
4170 if (lpmii->fMask & MIIM_CHECKMARKS)
4172 if (lpmii->fType & MFT_RADIOCHECK)
4173 menu->fType |= MFT_RADIOCHECK;
4175 menu->hCheckBit = lpmii->hbmpChecked;
4176 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4178 if (lpmii->fMask & MIIM_DATA)
4179 menu->dwItemData = lpmii->dwItemData;
4181 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4185 /**********************************************************************
4186 * SetMenuItemInfoA (USER32.@)
4188 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4189 const MENUITEMINFOA *lpmii)
4191 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4192 (const MENUITEMINFOW *)lpmii, FALSE);
4195 /**********************************************************************
4196 * SetMenuItemInfoW (USER32.@)
4198 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4199 const MENUITEMINFOW *lpmii)
4201 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4205 /**********************************************************************
4206 * SetMenuDefaultItem (USER32.@)
4209 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4215 TRACE("(%p,%d,%d)\n", hmenu, uItem, bypos);
4217 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4219 /* reset all default-item flags */
4221 for (i = 0; i < menu->nItems; i++, item++)
4223 item->fState &= ~MFS_DEFAULT;
4226 /* no default item */
4235 if ( uItem >= menu->nItems ) return FALSE;
4236 item[uItem].fState |= MFS_DEFAULT;
4241 for (i = 0; i < menu->nItems; i++, item++)
4243 if (item->wID == uItem)
4245 item->fState |= MFS_DEFAULT;
4254 /**********************************************************************
4255 * GetMenuDefaultItem (USER32.@)
4257 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4263 TRACE("(%p,%d,%d)\n", hmenu, bypos, flags);
4265 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4267 /* find default item */
4271 if (! item) return -1;
4273 while ( !( item->fState & MFS_DEFAULT ) )
4276 if (i >= menu->nItems ) return -1;
4279 /* default: don't return disabled items */
4280 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4282 /* search rekursiv when needed */
4283 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4286 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4287 if ( -1 != ret ) return ret;
4289 /* when item not found in submenu, return the popup item */
4291 return ( bypos ) ? i : item->wID;
4296 /**********************************************************************
4297 * InsertMenuItemA (USER32.@)
4299 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4300 const MENUITEMINFOA *lpmii)
4302 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4303 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4307 /**********************************************************************
4308 * InsertMenuItemW (USER32.@)
4310 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4311 const MENUITEMINFOW *lpmii)
4313 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4314 return SetMenuItemInfo_common(item, lpmii, TRUE);
4317 /**********************************************************************
4318 * CheckMenuRadioItem (USER32.@)
4321 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4322 UINT first, UINT last, UINT check,
4325 MENUITEM *mifirst, *milast, *micheck;
4326 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4328 TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos);
4330 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4331 milast = MENU_FindItem (&mlast, &last, bypos);
4332 micheck = MENU_FindItem (&mcheck, &check, bypos);
4334 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4335 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4336 micheck > milast || micheck < mifirst)
4339 while (mifirst <= milast)
4341 if (mifirst == micheck)
4343 mifirst->fType |= MFT_RADIOCHECK;
4344 mifirst->fState |= MFS_CHECKED;
4346 mifirst->fType &= ~MFT_RADIOCHECK;
4347 mifirst->fState &= ~MFS_CHECKED;
4356 /**********************************************************************
4357 * GetMenuItemRect (USER32.@)
4359 * ATTENTION: Here, the returned values in rect are the screen
4360 * coordinates of the item just like if the menu was
4361 * always on the upper left side of the application.
4364 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4367 POPUPMENU *itemMenu;
4371 TRACE("(%p,%p,%d,%p)\n", hwnd, hMenu, uItem, rect);
4373 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4374 referenceHwnd = hwnd;
4378 itemMenu = MENU_GetMenu(hMenu);
4379 if (itemMenu == NULL)
4382 if(itemMenu->hWnd == 0)
4384 referenceHwnd = itemMenu->hWnd;
4387 if ((rect == NULL) || (item == NULL))
4392 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4398 /**********************************************************************
4399 * SetMenuInfo (USER32.@)
4402 * MIM_APPLYTOSUBMENUS
4403 * actually use the items to draw the menu
4405 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4409 TRACE("(%p %p)\n", hMenu, lpmi);
4411 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4414 if (lpmi->fMask & MIM_BACKGROUND)
4415 menu->hbrBack = lpmi->hbrBack;
4417 if (lpmi->fMask & MIM_HELPID)
4418 menu->dwContextHelpID = lpmi->dwContextHelpID;
4420 if (lpmi->fMask & MIM_MAXHEIGHT)
4421 menu->cyMax = lpmi->cyMax;
4423 if (lpmi->fMask & MIM_MENUDATA)
4424 menu->dwMenuData = lpmi->dwMenuData;
4426 if (lpmi->fMask & MIM_STYLE)
4427 menu->dwStyle = lpmi->dwStyle;
4434 /**********************************************************************
4435 * GetMenuInfo (USER32.@)
4441 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4444 TRACE("(%p %p)\n", hMenu, lpmi);
4446 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4449 if (lpmi->fMask & MIM_BACKGROUND)
4450 lpmi->hbrBack = menu->hbrBack;
4452 if (lpmi->fMask & MIM_HELPID)
4453 lpmi->dwContextHelpID = menu->dwContextHelpID;
4455 if (lpmi->fMask & MIM_MAXHEIGHT)
4456 lpmi->cyMax = menu->cyMax;
4458 if (lpmi->fMask & MIM_MENUDATA)
4459 lpmi->dwMenuData = menu->dwMenuData;
4461 if (lpmi->fMask & MIM_STYLE)
4462 lpmi->dwStyle = menu->dwStyle;
4470 /**********************************************************************
4471 * SetMenuContextHelpId (USER32.@)
4473 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4477 TRACE("(%p 0x%08lx)\n", hMenu, dwContextHelpID);
4479 if ((menu = MENU_GetMenu(hMenu)))
4481 menu->dwContextHelpID = dwContextHelpID;
4488 /**********************************************************************
4489 * GetMenuContextHelpId (USER32.@)
4491 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4495 TRACE("(%p)\n", hMenu);
4497 if ((menu = MENU_GetMenu(hMenu)))
4499 return menu->dwContextHelpID;
4504 /**********************************************************************
4505 * MenuItemFromPoint (USER32.@)
4507 INT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4509 POPUPMENU *menu = MENU_GetMenu(hMenu);
4512 /*FIXME: Do we have to handle hWnd here? */
4513 if (!menu) return -1;
4514 if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
4519 /**********************************************************************
4520 * translate_accelerator
4522 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4523 BYTE fVirt, WORD key, WORD cmd )
4528 if (wParam != key) return FALSE;
4530 if (GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4531 if (GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4532 if (GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4534 if (message == WM_CHAR || message == WM_SYSCHAR)
4536 if ( !(fVirt & FVIRTKEY) && (mask & FALT) == (fVirt & FALT) )
4538 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4544 if(fVirt & FVIRTKEY)
4546 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4547 wParam, 0xff & HIWORD(lParam));
4549 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4550 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4554 if (!(lParam & 0x01000000)) /* no special_key */
4556 if ((fVirt & FALT) && (lParam & 0x20000000))
4557 { /* ^^ ALT pressed */
4558 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4567 if (message == WM_KEYUP || message == WM_SYSKEYUP)
4571 HMENU hMenu, hSubMenu, hSysMenu;
4572 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4574 hMenu = (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4575 hSysMenu = get_win_sys_menu( hWnd );
4577 /* find menu item and ask application to initialize it */
4578 /* 1. in the system menu */
4579 hSubMenu = hSysMenu;
4581 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4585 if (!IsWindowEnabled(hWnd))
4589 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4590 if(hSubMenu != hSysMenu)
4592 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4593 TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4594 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4596 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4599 else /* 2. in the window's menu */
4603 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4607 if (!IsWindowEnabled(hWnd))
4611 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4612 if(hSubMenu != hMenu)
4614 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4615 TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
4616 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4618 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4625 if (uSysStat != (UINT)-1)
4627 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4634 if (uStat != (UINT)-1)
4640 if (uStat & (MF_DISABLED|MF_GRAYED))
4652 if( mesg==WM_COMMAND )
4654 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4655 SendMessageW(hWnd, mesg, 0x10000 | cmd, 0L);
4657 else if( mesg==WM_SYSCOMMAND )
4659 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4660 SendMessageW(hWnd, mesg, cmd, 0x00010000L);
4664 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4665 * #0: unknown (please report!)
4666 * #1: for WM_KEYUP,WM_SYSKEYUP
4667 * #2: mouse is captured
4668 * #3: window is disabled
4669 * #4: it's a disabled system menu option
4670 * #5: it's a menu option, but window is iconic
4671 * #6: it's a menu option, but disabled
4673 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4675 ERR_(accel)(" unknown reason - please report!\n");
4680 /**********************************************************************
4681 * TranslateAccelerator (USER32.@)
4682 * TranslateAcceleratorA (USER32.@)
4684 INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg )
4687 LPACCEL16 lpAccelTbl;
4691 if (!hWnd || !msg) return 0;
4693 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
4695 WARN_(accel)("invalid accel handle=%p\n", hAccel);
4699 wParam = msg->wParam;
4701 switch (msg->message)
4710 char ch = LOWORD(wParam);
4712 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
4713 wParam = MAKEWPARAM(wch, HIWORD(wParam));
4721 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4722 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4726 if (translate_accelerator( hWnd, msg->message, wParam, msg->lParam,
4727 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4729 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
4734 /**********************************************************************
4735 * TranslateAcceleratorW (USER32.@)
4737 INT WINAPI TranslateAcceleratorW( HWND hWnd, HACCEL hAccel, LPMSG msg )
4740 LPACCEL16 lpAccelTbl;
4743 if (!hWnd || !msg) return 0;
4745 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
4747 WARN_(accel)("invalid accel handle=%p\n", hAccel);
4751 switch (msg->message)
4763 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4764 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4768 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
4769 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4771 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);