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 IS_SYSTEM_POPUP(menu) \
149 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
151 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
152 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
153 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
154 MF_POPUP | MF_SYSMENU | MF_HELP)
155 #define STATE_MASK (~TYPE_MASK)
157 /* Dimension of the menu bitmaps */
158 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
160 static HBITMAP hStdMnArrow = 0;
161 static HBITMAP hBmpSysMenu = 0;
163 static HBRUSH hShadeBrush = 0;
164 static HFONT hMenuFont = 0;
165 static HFONT hMenuFontBold = 0;
167 static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
169 /* Use global popup window because there's no way 2 menus can
170 * be tracked at the same time. */
171 static HWND top_popup;
173 /* Flag set by EndMenu() to force an exit from menu tracking */
174 static BOOL fEndMenu = FALSE;
176 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
178 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont);
180 /*********************************************************************
181 * menu class descriptor
183 const struct builtin_class_descr MENU_builtin_class =
185 POPUPMENU_CLASS_ATOMA, /* name */
186 CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, /* style */
187 NULL, /* procA (winproc is Unicode only) */
188 PopupMenuWndProc, /* procW */
189 sizeof(HMENU), /* extra */
190 IDC_ARROW, /* cursor */
191 (HBRUSH)(COLOR_MENU+1) /* brush */
195 /***********************************************************************
196 * debug_print_menuitem
198 * Print a menuitem in readable form.
201 #define debug_print_menuitem(pre, mp, post) \
202 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
204 #define MENUOUT(text) \
205 DPRINTF("%s%s", (count++ ? "," : ""), (text))
207 #define MENUFLAG(bit,text) \
209 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
212 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
215 TRACE("%s ", prefix);
217 UINT flags = mp->fType;
218 int type = MENU_ITEM_TYPE(flags);
219 DPRINTF( "{ ID=0x%x", mp->wID);
220 if (flags & MF_POPUP)
221 DPRINTF( ", Sub=%p", mp->hSubMenu);
225 if (type == MFT_STRING)
227 else if (type == MFT_SEPARATOR)
229 else if (type == MFT_OWNERDRAW)
231 else if (type == MFT_BITMAP)
237 MENUFLAG(MF_POPUP, "pop");
238 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
239 MENUFLAG(MFT_MENUBREAK, "brk");
240 MENUFLAG(MFT_RADIOCHECK, "radio");
241 MENUFLAG(MFT_RIGHTORDER, "rorder");
242 MENUFLAG(MF_SYSMENU, "sys");
243 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
246 DPRINTF( "+0x%x", flags);
251 DPRINTF( ", State=");
252 MENUFLAG(MFS_GRAYED, "grey");
253 MENUFLAG(MFS_DEFAULT, "default");
254 MENUFLAG(MFS_DISABLED, "dis");
255 MENUFLAG(MFS_CHECKED, "check");
256 MENUFLAG(MFS_HILITE, "hi");
257 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
258 MENUFLAG(MF_MOUSESELECT, "mouse");
260 DPRINTF( "+0x%x", flags);
263 DPRINTF( ", Chk=%p", mp->hCheckBit);
265 DPRINTF( ", Unc=%p", mp->hUnCheckBit);
267 if (type == MFT_STRING) {
269 DPRINTF( ", Text=%s", debugstr_w(mp->text));
271 DPRINTF( ", Text=Null");
272 } else if (mp->text == NULL)
275 DPRINTF( ", Text=%p", mp->text);
277 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
283 DPRINTF(" %s\n", postfix);
290 /***********************************************************************
293 * Validate the given menu handle and returns the menu structure pointer.
295 static POPUPMENU *MENU_GetMenu(HMENU hMenu)
297 POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
298 if (!menu || menu->wMagic != MENU_MAGIC)
300 WARN("invalid menu handle=%p, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
306 /***********************************************************************
309 * Get the system menu of a window
311 static HMENU get_win_sys_menu( HWND hwnd )
314 WND *win = WIN_GetPtr( hwnd );
315 if (win && win != WND_OTHER_PROCESS)
318 WIN_ReleasePtr( win );
323 /***********************************************************************
326 * Return the default system menu.
328 static HMENU MENU_CopySysPopup(void)
330 static const WCHAR sysmenuW[] = {'S','Y','S','M','E','N','U',0};
331 HMENU hMenu = LoadMenuW(user32_module, sysmenuW);
334 POPUPMENU* menu = MENU_GetMenu(hMenu);
335 menu->wFlags |= MF_SYSMENU | MF_POPUP;
336 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
339 ERR("Unable to load default system menu\n" );
341 TRACE("returning %p.\n", hMenu );
347 /**********************************************************************
350 * Create a copy of the system menu. System menu in Windows is
351 * a special menu bar with the single entry - system menu popup.
352 * This popup is presented to the outside world as a "system menu".
353 * However, the real system menu handle is sometimes seen in the
354 * WM_MENUSELECT parameters (and Word 6 likes it this way).
356 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
360 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd, hPopupMenu);
361 if ((hMenu = CreateMenu()))
363 POPUPMENU *menu = MENU_GetMenu(hMenu);
364 menu->wFlags = MF_SYSMENU;
365 menu->hWnd = WIN_GetFullHandle( hWnd );
366 TRACE("hWnd %p (hMenu %p)\n", menu->hWnd, hMenu);
368 if (hPopupMenu == (HMENU)(-1))
369 hPopupMenu = MENU_CopySysPopup();
370 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
374 InsertMenuW( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION,
375 (UINT_PTR)hPopupMenu, NULL );
377 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
378 menu->items[0].fState = 0;
379 if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
381 TRACE("hMenu=%p (hPopup %p)\n", hMenu, hPopupMenu );
384 DestroyMenu( hMenu );
386 ERR("failed to load system menu!\n");
391 /***********************************************************************
394 * Menus initialisation.
399 NONCLIENTMETRICSW ncm;
401 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
406 /* Load menu bitmaps */
407 hStdMnArrow = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
408 /* Load system buttons bitmaps */
409 hBmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
414 GetObjectW( hStdMnArrow, sizeof(bm), &bm );
415 arrow_bitmap_width = bm.bmWidth;
416 arrow_bitmap_height = bm.bmHeight;
420 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
423 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
426 DeleteObject( hBitmap );
427 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
430 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
431 if (!(SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0)))
434 if (!(hMenuFont = CreateFontIndirectW( &ncm.lfMenuFont )))
437 ncm.lfMenuFont.lfWeight += 300;
438 if ( ncm.lfMenuFont.lfWeight > 1000)
439 ncm.lfMenuFont.lfWeight = 1000;
441 if (!(hMenuFontBold = CreateFontIndirectW( &ncm.lfMenuFont )))
447 /***********************************************************************
448 * MENU_InitSysMenuPopup
450 * Grey the appropriate items in System menu.
452 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
456 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
457 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
458 gray = ((style & WS_MAXIMIZE) != 0);
459 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
460 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
461 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
462 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
463 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
464 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
465 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
466 gray = (clsStyle & CS_NOCLOSE) != 0;
468 /* The menu item must keep its state if it's disabled */
470 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
474 /******************************************************************************
476 * UINT MENU_GetStartOfNextColumn(
479 *****************************************************************************/
481 static UINT MENU_GetStartOfNextColumn(
484 POPUPMENU *menu = MENU_GetMenu(hMenu);
488 return NO_SELECTED_ITEM;
490 i = menu->FocusedItem + 1;
491 if( i == NO_SELECTED_ITEM )
494 for( ; i < menu->nItems; ++i ) {
495 if (menu->items[i].fType & MF_MENUBARBREAK)
499 return NO_SELECTED_ITEM;
503 /******************************************************************************
505 * UINT MENU_GetStartOfPrevColumn(
508 *****************************************************************************/
510 static UINT MENU_GetStartOfPrevColumn(
513 POPUPMENU *menu = MENU_GetMenu(hMenu);
517 return NO_SELECTED_ITEM;
519 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
520 return NO_SELECTED_ITEM;
522 /* Find the start of the column */
524 for(i = menu->FocusedItem; i != 0 &&
525 !(menu->items[i].fType & MF_MENUBARBREAK);
529 return NO_SELECTED_ITEM;
531 for(--i; i != 0; --i) {
532 if (menu->items[i].fType & MF_MENUBARBREAK)
536 TRACE("ret %d.\n", i );
543 /***********************************************************************
546 * Find a menu item. Return a pointer on the item, and modifies *hmenu
547 * in case the item was in a sub-menu.
549 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
554 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
555 if (wFlags & MF_BYPOSITION)
557 if (*nPos >= menu->nItems) return NULL;
558 return &menu->items[*nPos];
562 MENUITEM *item = menu->items;
563 for (i = 0; i < menu->nItems; i++, item++)
565 if (item->wID == *nPos)
570 else if (item->fType & MF_POPUP)
572 HMENU hsubmenu = item->hSubMenu;
573 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
585 /***********************************************************************
588 * Find a Sub menu. Return the position of the submenu, and modifies
589 * *hmenu in case it is found in another sub-menu.
590 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
592 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
597 if (((*hmenu)==(HMENU)0xffff) ||
598 (!(menu = MENU_GetMenu(*hmenu))))
599 return NO_SELECTED_ITEM;
601 for (i = 0; i < menu->nItems; i++, item++) {
602 if(!(item->fType & MF_POPUP)) continue;
603 if (item->hSubMenu == hSubTarget) {
607 HMENU hsubmenu = item->hSubMenu;
608 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
609 if (pos != NO_SELECTED_ITEM) {
615 return NO_SELECTED_ITEM;
618 /***********************************************************************
621 static void MENU_FreeItemData( MENUITEM* item )
624 if (IS_STRING_ITEM(item->fType) && item->text)
625 HeapFree( GetProcessHeap(), 0, item->text );
628 /***********************************************************************
629 * MENU_FindItemByCoords
631 * Find the item at the specified coordinates (screen coords). Does
632 * not work for child windows and therefore should not be called for
633 * an arbitrary system menu.
635 static MENUITEM *MENU_FindItemByCoords( const POPUPMENU *menu,
636 POINT pt, UINT *pos )
642 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
643 pt.x -= wrect.left;pt.y -= wrect.top;
645 for (i = 0; i < menu->nItems; i++, item++)
647 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
648 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
658 /***********************************************************************
661 * Find the menu item selected by a key press.
662 * Return item id, -1 if none, -2 if we should close the menu.
664 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
665 WCHAR key, BOOL forceMenuChar )
667 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)key, key, hmenu );
669 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
673 POPUPMENU *menu = MENU_GetMenu( hmenu );
674 MENUITEM *item = menu->items;
681 for (i = 0; i < menu->nItems; i++, item++)
683 if (IS_STRING_ITEM(item->fType) && item->text)
685 WCHAR *p = item->text - 2;
688 p = strchrW (p + 2, '&');
690 while (p != NULL && p [1] == '&');
691 if (p && (toupperW(p[1]) == toupperW(key))) return i;
695 menuchar = SendMessageW( hwndOwner, WM_MENUCHAR,
696 MAKEWPARAM( key, menu->wFlags ), (LPARAM)hmenu );
697 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
698 if (HIWORD(menuchar) == 1) return (UINT)(-2);
704 /***********************************************************************
705 * MENU_GetBitmapItemSize
707 * Get the size of a bitmap item.
709 static void MENU_GetBitmapItemSize( UINT id, DWORD data, SIZE *size )
712 HBITMAP bmp = (HBITMAP)id;
714 size->cx = size->cy = 0;
716 /* check if there is a magic menu item associated with this item */
717 if (id && IS_MAGIC_ITEM( id ))
721 case (INT_PTR)HBMMENU_SYSTEM:
728 case (INT_PTR)HBMMENU_MBAR_RESTORE:
729 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
730 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
731 case (INT_PTR)HBMMENU_MBAR_CLOSE:
732 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
733 size->cx = GetSystemMetrics( SM_CYMENU ) - 4;
736 case (INT_PTR)HBMMENU_CALLBACK:
737 case (INT_PTR)HBMMENU_POPUP_CLOSE:
738 case (INT_PTR)HBMMENU_POPUP_RESTORE:
739 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
740 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
742 FIXME("Magic 0x%08x not implemented\n", id);
746 if (GetObjectW(bmp, sizeof(bm), &bm ))
748 size->cx = bm.bmWidth;
749 size->cy = bm.bmHeight;
753 /***********************************************************************
754 * MENU_DrawBitmapItem
756 * Draw a bitmap item.
758 static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar )
763 HBITMAP bmp = (HBITMAP)lpitem->text;
764 int w = rect->right - rect->left;
765 int h = rect->bottom - rect->top;
769 /* Check if there is a magic menu item associated with this item */
770 if (lpitem->text && IS_MAGIC_ITEM(lpitem->text))
775 switch(LOWORD(lpitem->text))
777 case (INT_PTR)HBMMENU_SYSTEM:
778 if (lpitem->dwItemData)
780 bmp = (HBITMAP)lpitem->dwItemData;
781 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
786 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
787 /* only use right half of the bitmap */
788 bmp_xoffset = bm.bmWidth / 2;
789 bm.bmWidth -= bmp_xoffset;
792 case (INT_PTR)HBMMENU_MBAR_RESTORE:
793 flags = DFCS_CAPTIONRESTORE;
795 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
796 flags = DFCS_CAPTIONMIN;
798 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
799 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
801 case (INT_PTR)HBMMENU_MBAR_CLOSE:
802 flags = DFCS_CAPTIONCLOSE;
804 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
805 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
807 case (INT_PTR)HBMMENU_CALLBACK:
808 case (INT_PTR)HBMMENU_POPUP_CLOSE:
809 case (INT_PTR)HBMMENU_POPUP_RESTORE:
810 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
811 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
813 FIXME("Magic 0x%08x not implemented\n", LOWORD(lpitem->text));
817 InflateRect( &r, -1, -1 );
818 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
819 DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
823 if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
826 hdcMem = CreateCompatibleDC( hdc );
827 SelectObject( hdcMem, bmp );
829 /* handle fontsize > bitmap_height */
830 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
832 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text)) ? NOTSRCCOPY : SRCCOPY;
833 if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
834 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
835 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
840 /***********************************************************************
843 * Calculate the size of the menu item and store it in lpitem->rect.
845 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
846 INT orgX, INT orgY, BOOL menuBar )
849 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
851 TRACE("dc=%p owner=%p (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
852 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
853 (menuBar ? " (MenuBar)" : ""));
855 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
857 if (lpitem->fType & MF_OWNERDRAW)
860 ** Experimentation under Windows reveals that an owner-drawn
861 ** menu is expected to return the size of the content part of
862 ** the menu item, not including the checkmark nor the submenu
863 ** arrow. Windows adds those values itself and returns the
864 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
866 MEASUREITEMSTRUCT mis;
867 mis.CtlType = ODT_MENU;
869 mis.itemID = lpitem->wID;
870 mis.itemData = (DWORD)lpitem->dwItemData;
873 SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
874 lpitem->rect.right += mis.itemWidth;
878 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
881 /* under at least win95 you seem to be given a standard
882 height for the menu and the height value is ignored */
883 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
886 lpitem->rect.bottom += mis.itemHeight;
888 TRACE("id=%04x size=%dx%d\n",
889 lpitem->wID, mis.itemWidth, mis.itemHeight);
890 /* Fall through to get check/arrow width calculation. */
893 if (lpitem->fType & MF_SEPARATOR)
895 lpitem->rect.bottom += SEPARATOR_HEIGHT;
901 lpitem->rect.right += 2 * check_bitmap_width;
902 if (lpitem->fType & MF_POPUP)
903 lpitem->rect.right += arrow_bitmap_width;
906 if (lpitem->fType & MF_OWNERDRAW)
909 if (IS_BITMAP_ITEM(lpitem->fType))
913 MENU_GetBitmapItemSize( (int)lpitem->text, lpitem->dwItemData, &size );
914 lpitem->rect.right += size.cx;
915 lpitem->rect.bottom += size.cy;
916 /* Leave space for the sunken border */
917 lpitem->rect.right += 2;
918 lpitem->rect.bottom += 2;
922 /* it must be a text item - unless it's the system menu */
923 if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
926 GetTextExtentPoint32W(hdc, lpitem->text, strlenW(lpitem->text), &size);
928 lpitem->rect.right += size.cx;
929 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
934 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
936 else if ((p = strchrW( lpitem->text, '\t' )) != NULL)
938 /* Item contains a tab (only meaningful in popup menus) */
939 GetTextExtentPoint32W(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
940 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
941 lpitem->rect.right += MENU_TAB_SPACE;
945 if (strchrW( lpitem->text, '\b' ))
946 lpitem->rect.right += MENU_TAB_SPACE;
947 lpitem->xTab = lpitem->rect.right - check_bitmap_width
948 - arrow_bitmap_width;
951 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
955 /***********************************************************************
956 * MENU_PopupMenuCalcSize
958 * Calculate the size of a popup menu.
960 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
965 int orgX, orgY, maxX, maxTab, maxTabWidth;
967 lppop->Width = lppop->Height = 0;
968 if (lppop->nItems == 0) return;
971 SelectObject( hdc, hMenuFont);
976 while (start < lppop->nItems)
978 lpitem = &lppop->items[start];
982 maxTab = maxTabWidth = 0;
984 /* Parse items until column break or end of menu */
985 for (i = start; i < lppop->nItems; i++, lpitem++)
988 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
990 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
992 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
993 maxX = max( maxX, lpitem->rect.right );
994 orgY = lpitem->rect.bottom;
995 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
997 maxTab = max( maxTab, lpitem->xTab );
998 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
1002 /* Finish the column (set all items to the largest width found) */
1003 maxX = max( maxX, maxTab + maxTabWidth );
1004 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
1006 lpitem->rect.right = maxX;
1007 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1008 lpitem->xTab = maxTab;
1011 lppop->Height = max( lppop->Height, orgY );
1014 lppop->Width = maxX;
1016 /* space for 3d border */
1020 ReleaseDC( 0, hdc );
1024 /***********************************************************************
1025 * MENU_MenuBarCalcSize
1027 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1028 * height is off by 1 pixel which causes lengthy window relocations when
1029 * active document window is maximized/restored.
1031 * Calculate the size of the menu bar.
1033 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1034 LPPOPUPMENU lppop, HWND hwndOwner )
1037 int start, i, orgX, orgY, maxY, helpPos;
1039 if ((lprect == NULL) || (lppop == NULL)) return;
1040 if (lppop->nItems == 0) return;
1041 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1042 lprect->left, lprect->top, lprect->right, lprect->bottom);
1043 lppop->Width = lprect->right - lprect->left;
1045 maxY = lprect->top+1;
1048 while (start < lppop->nItems)
1050 lpitem = &lppop->items[start];
1051 orgX = lprect->left;
1054 /* Parse items until line break or end of menu */
1055 for (i = start; i < lppop->nItems; i++, lpitem++)
1057 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
1059 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1061 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1063 debug_print_menuitem (" item: ", lpitem, "");
1064 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1066 if (lpitem->rect.right > lprect->right)
1068 if (i != start) break;
1069 else lpitem->rect.right = lprect->right;
1071 maxY = max( maxY, lpitem->rect.bottom );
1072 orgX = lpitem->rect.right;
1075 /* Finish the line (set all items to the largest height found) */
1076 while (start < i) lppop->items[start++].rect.bottom = maxY;
1079 lprect->bottom = maxY;
1080 lppop->Height = lprect->bottom - lprect->top;
1082 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1083 /* the last item (if several lines, only move the last line) */
1084 lpitem = &lppop->items[lppop->nItems-1];
1085 orgY = lpitem->rect.top;
1086 orgX = lprect->right;
1087 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1088 if ( (helpPos==-1) || (helpPos>i) )
1090 if (lpitem->rect.top != orgY) break; /* Other line */
1091 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1092 lpitem->rect.left += orgX - lpitem->rect.right;
1093 lpitem->rect.right = orgX;
1094 orgX = lpitem->rect.left;
1098 /***********************************************************************
1101 * Draw a single menu item.
1103 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1104 UINT height, BOOL menuBar, UINT odaction )
1108 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1110 if (lpitem->fType & MF_SYSMENU)
1112 if( !IsIconic(hwnd) )
1113 NC_DrawSysButton( hwnd, hdc, lpitem->fState & (MF_HILITE | MF_MOUSESELECT) );
1119 if (lpitem->fState & MF_HILITE)
1122 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1123 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1125 if(lpitem->fState & MF_GRAYED)
1126 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1128 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1129 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1134 if (lpitem->fState & MF_GRAYED)
1135 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1137 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1138 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1141 if (lpitem->fType & MF_OWNERDRAW)
1144 ** Experimentation under Windows reveals that an owner-drawn
1145 ** menu is given the rectangle which includes the space it requested
1146 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1147 ** and a popup-menu arrow. This is the value of lpitem->rect.
1148 ** Windows will leave all drawing to the application except for
1149 ** the popup-menu arrow. Windows always draws that itself, after
1150 ** the menu owner has finished drawing.
1154 dis.CtlType = ODT_MENU;
1156 dis.itemID = lpitem->wID;
1157 dis.itemData = (DWORD)lpitem->dwItemData;
1159 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1160 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED|ODS_DISABLED;
1161 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1162 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1163 dis.hwndItem = (HWND)hmenu;
1165 dis.rcItem = lpitem->rect;
1166 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1167 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner,
1168 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1169 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1171 SendMessageW( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1172 /* Fall through to draw popup-menu arrow */
1175 TRACE("rect={%ld,%ld,%ld,%ld}\n", lpitem->rect.left, lpitem->rect.top,
1176 lpitem->rect.right,lpitem->rect.bottom);
1178 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1180 rect = lpitem->rect;
1182 if (!(lpitem->fType & MF_OWNERDRAW))
1184 if (lpitem->fState & MF_HILITE)
1187 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1189 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1192 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1195 SetBkMode( hdc, TRANSPARENT );
1197 if (!(lpitem->fType & MF_OWNERDRAW))
1199 /* vertical separator */
1200 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1204 rc.bottom = height - 3;
1205 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1208 /* horizontal separator */
1209 if (lpitem->fType & MF_SEPARATOR)
1214 rc.top += SEPARATOR_HEIGHT / 2;
1215 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1220 /* helper lines for debugging */
1221 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1222 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1223 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1224 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1229 INT y = rect.top + rect.bottom;
1230 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1231 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1233 if (!(lpitem->fType & MF_OWNERDRAW))
1235 /* Draw the check mark
1238 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1240 HBITMAP bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
1241 if (bm) /* we have a custom bitmap */
1243 HDC hdcMem = CreateCompatibleDC( hdc );
1244 SelectObject( hdcMem, bm );
1245 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1246 check_bitmap_width, check_bitmap_height,
1247 hdcMem, 0, 0, SRCCOPY );
1250 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1253 HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1254 HDC hdcMem = CreateCompatibleDC( hdc );
1255 SelectObject( hdcMem, bm );
1256 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
1257 DrawFrameControl( hdcMem, &r, DFC_MENU,
1258 (lpitem->fType & MFT_RADIOCHECK) ?
1259 DFCS_MENUBULLET : DFCS_MENUCHECK );
1260 BitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
1261 hdcMem, 0, 0, SRCCOPY );
1267 /* Draw the popup-menu arrow */
1268 if (lpitem->fType & MF_POPUP)
1270 HDC hdcMem = CreateCompatibleDC( hdc );
1271 HBITMAP hOrigBitmap;
1273 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1274 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1275 (y - arrow_bitmap_height) / 2,
1276 arrow_bitmap_width, arrow_bitmap_height,
1277 hdcMem, 0, 0, SRCCOPY );
1278 SelectObject( hdcMem, hOrigBitmap );
1282 rect.left += check_bitmap_width;
1283 rect.right -= arrow_bitmap_width;
1286 /* Done for owner-drawn */
1287 if (lpitem->fType & MF_OWNERDRAW)
1290 /* Draw the item text or bitmap */
1291 if (IS_BITMAP_ITEM(lpitem->fType))
1293 MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
1297 /* No bitmap - process text if present */
1298 else if (IS_STRING_ITEM(lpitem->fType))
1303 UINT uFormat = (menuBar) ?
1304 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1305 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1307 if ( lpitem->fState & MFS_DEFAULT )
1309 hfontOld = SelectObject( hdc, hMenuFontBold);
1314 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1315 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1318 for (i = 0; lpitem->text[i]; i++)
1319 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1322 if(lpitem->fState & MF_GRAYED)
1324 if (!(lpitem->fState & MF_HILITE) )
1326 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1327 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1328 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1329 --rect.left; --rect.top; --rect.right; --rect.bottom;
1331 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1334 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
1336 /* paint the shortcut text */
1337 if (!menuBar && lpitem->text[i]) /* There's a tab or flush-right char */
1339 if (lpitem->text[i] == '\t')
1341 rect.left = lpitem->xTab;
1342 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1346 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1349 if(lpitem->fState & MF_GRAYED)
1351 if (!(lpitem->fState & MF_HILITE) )
1353 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1354 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1355 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1356 --rect.left; --rect.top; --rect.right; --rect.bottom;
1358 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1360 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1364 SelectObject (hdc, hfontOld);
1369 /***********************************************************************
1370 * MENU_DrawPopupMenu
1372 * Paint a popup menu.
1374 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1376 HBRUSH hPrevBrush = 0;
1379 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
1381 GetClientRect( hwnd, &rect );
1383 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1384 && (SelectObject( hdc, hMenuFont)))
1388 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1390 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1395 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1397 /* draw menu items */
1399 menu = MENU_GetMenu( hmenu );
1400 if (menu && menu->nItems)
1405 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1406 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1407 menu->Height, FALSE, ODA_DRAWENTIRE );
1412 SelectObject( hdc, hPrevBrush );
1417 /***********************************************************************
1420 * Paint a menu bar. Returns the height of the menu bar.
1421 * called from [windows/nonclient.c]
1423 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1428 HMENU hMenu = GetMenu(hwnd);
1430 lppop = MENU_GetMenu( hMenu );
1431 if (lppop == NULL || lprect == NULL)
1433 return GetSystemMetrics(SM_CYMENU);
1438 hfontOld = SelectObject( hDC, hMenuFont);
1440 if (lppop->Height == 0)
1441 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1443 lprect->bottom = lprect->top + lppop->Height;
1445 if (hfontOld) SelectObject( hDC, hfontOld);
1446 return lppop->Height;
1449 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
1453 /***********************************************************************
1456 * Display a popup menu.
1458 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1459 INT x, INT y, INT xanchor, INT yanchor )
1464 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1465 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1467 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1468 if (menu->FocusedItem != NO_SELECTED_ITEM)
1470 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1471 menu->FocusedItem = NO_SELECTED_ITEM;
1474 /* store the owner for DrawItem */
1475 menu->hwndOwner = hwndOwner;
1477 MENU_PopupMenuCalcSize( menu, hwndOwner );
1479 /* adjust popup menu pos so that it fits within the desktop */
1481 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1482 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1484 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1487 x -= width - xanchor;
1488 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1489 x = GetSystemMetrics(SM_CXSCREEN) - width;
1493 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1496 y -= height + yanchor;
1497 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1498 y = GetSystemMetrics(SM_CYSCREEN) - height;
1502 /* NOTE: In Windows, top menu popup is not owned. */
1503 menu->hWnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL,
1504 WS_POPUP, x, y, width, height,
1505 hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
1507 if( !menu->hWnd ) return FALSE;
1508 if (!top_popup) top_popup = menu->hWnd;
1510 /* Display the window */
1512 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1513 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1514 UpdateWindow( menu->hWnd );
1519 /***********************************************************************
1522 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1523 BOOL sendMenuSelect, HMENU topmenu )
1528 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1530 lppop = MENU_GetMenu( hmenu );
1531 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
1533 if (lppop->FocusedItem == wIndex) return;
1534 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1535 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1536 if (!top_popup) top_popup = lppop->hWnd;
1538 SelectObject( hdc, hMenuFont);
1540 /* Clear previous highlighted item */
1541 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1543 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1544 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1545 lppop->Height, !(lppop->wFlags & MF_POPUP),
1549 /* Highlight new item (if any) */
1550 lppop->FocusedItem = wIndex;
1551 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1553 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1554 lppop->items[wIndex].fState |= MF_HILITE;
1555 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1556 &lppop->items[wIndex], lppop->Height,
1557 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1561 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1562 SendMessageW( hwndOwner, WM_MENUSELECT,
1563 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1564 ip->fType | ip->fState |
1565 (lppop->wFlags & MF_SYSMENU)), (LPARAM)hmenu);
1568 else if (sendMenuSelect) {
1571 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1572 POPUPMENU *ptm = MENU_GetMenu( topmenu );
1573 MENUITEM *ip = &ptm->items[pos];
1574 SendMessageW( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1575 ip->fType | ip->fState |
1576 (ptm->wFlags & MF_SYSMENU)), (LPARAM)topmenu);
1580 ReleaseDC( lppop->hWnd, hdc );
1584 /***********************************************************************
1585 * MENU_MoveSelection
1587 * Moves currently selected item according to the offset parameter.
1588 * If there is no selection then it should select the last item if
1589 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1591 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1596 TRACE("hwnd=%p hmenu=%p off=0x%04x\n", hwndOwner, hmenu, offset);
1598 menu = MENU_GetMenu( hmenu );
1599 if ((!menu) || (!menu->items)) return;
1601 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1603 if( menu->nItems == 1 ) return; else
1604 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1606 if (!(menu->items[i].fType & MF_SEPARATOR))
1608 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1613 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1614 i >= 0 && i < menu->nItems ; i += offset)
1615 if (!(menu->items[i].fType & MF_SEPARATOR))
1617 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1623 /**********************************************************************
1626 * Set an item's flags, id and text ptr. Called by InsertMenu() and
1629 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id,
1632 LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1634 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1635 TRACE("flags=%x str=%p\n", flags, str);
1637 if (IS_STRING_ITEM(flags))
1641 flags |= MF_SEPARATOR;
1647 /* Item beginning with a backspace is a help item */
1653 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1655 strcpyW( text, str );
1659 else if (IS_BITMAP_ITEM(flags))
1660 item->text = (LPWSTR)HBITMAP_32(LOWORD(str));
1661 else item->text = NULL;
1663 if (flags & MF_OWNERDRAW)
1664 item->dwItemData = (DWORD)str;
1666 item->dwItemData = 0;
1668 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != (HMENU)id) )
1669 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1671 if (flags & MF_POPUP)
1673 POPUPMENU *menu = MENU_GetMenu((HMENU)id);
1674 if (menu) menu->wFlags |= MF_POPUP;
1686 if (flags & MF_POPUP) item->hSubMenu = (HMENU)id;
1688 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1689 flags |= MF_POPUP; /* keep popup */
1691 item->fType = flags & TYPE_MASK;
1692 item->fState = (flags & STATE_MASK) &
1693 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1696 /* Don't call SetRectEmpty here! */
1699 HeapFree( GetProcessHeap(), 0, prevText );
1701 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1706 /**********************************************************************
1709 * Insert (allocate) a new item into a menu.
1711 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1716 if (!(menu = MENU_GetMenu(hMenu)))
1719 /* Find where to insert new item */
1721 if (flags & MF_BYPOSITION) {
1722 if (pos > menu->nItems)
1725 if (!MENU_FindItem( &hMenu, &pos, flags ))
1728 if (!(menu = MENU_GetMenu( hMenu )))
1733 /* Create new items array */
1735 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
1738 WARN("allocation failed\n" );
1741 if (menu->nItems > 0)
1743 /* Copy the old array into the new one */
1744 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1745 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1746 (menu->nItems-pos)*sizeof(MENUITEM) );
1747 HeapFree( GetProcessHeap(), 0, menu->items );
1749 menu->items = newItems;
1751 memset( &newItems[pos], 0, sizeof(*newItems) );
1752 menu->Height = 0; /* force size recalculate */
1753 return &newItems[pos];
1757 /**********************************************************************
1758 * MENU_ParseResource
1760 * Parse a standard menu resource and add items to the menu.
1761 * Return a pointer to the end of the resource.
1763 * NOTE: flags is equivalent to the mtOption field
1765 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1772 flags = GET_WORD(res);
1773 res += sizeof(WORD);
1774 if (!(flags & MF_POPUP))
1777 res += sizeof(WORD);
1780 if (!unicode) res += strlen(str) + 1;
1781 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1782 if (flags & MF_POPUP)
1784 HMENU hSubMenu = CreatePopupMenu();
1785 if (!hSubMenu) return NULL;
1786 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1788 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1789 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1791 else /* Not a popup */
1793 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1794 else AppendMenuW( hMenu, flags, id,
1795 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1797 } while (!(flags & MF_END));
1802 /**********************************************************************
1803 * MENUEX_ParseResource
1805 * Parse an extended menu resource and add items to the menu.
1806 * Return a pointer to the end of the resource.
1808 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1814 mii.cbSize = sizeof(mii);
1815 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1816 mii.fType = GET_DWORD(res);
1817 res += sizeof(DWORD);
1818 mii.fState = GET_DWORD(res);
1819 res += sizeof(DWORD);
1820 mii.wID = GET_DWORD(res);
1821 res += sizeof(DWORD);
1822 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1823 res += sizeof(WORD);
1824 /* Align the text on a word boundary. */
1825 res += (~((int)res - 1)) & 1;
1826 mii.dwTypeData = (LPWSTR) res;
1827 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
1828 /* Align the following fields on a dword boundary. */
1829 res += (~((int)res - 1)) & 3;
1831 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1832 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
1834 if (resinfo & 1) { /* Pop-up? */
1835 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1836 res += sizeof(DWORD);
1837 mii.hSubMenu = CreatePopupMenu();
1840 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
1841 DestroyMenu(mii.hSubMenu);
1844 mii.fMask |= MIIM_SUBMENU;
1845 mii.fType |= MF_POPUP;
1847 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
1849 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
1850 mii.wID, mii.fType);
1851 mii.fType |= MF_SEPARATOR;
1853 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
1854 } while (!(resinfo & MF_END));
1859 /***********************************************************************
1862 * Return the handle of the selected sub-popup menu (if any).
1864 static HMENU MENU_GetSubPopup( HMENU hmenu )
1869 menu = MENU_GetMenu( hmenu );
1871 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
1873 item = &menu->items[menu->FocusedItem];
1874 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
1875 return item->hSubMenu;
1880 /***********************************************************************
1881 * MENU_HideSubPopups
1883 * Hide the sub-popup menus of this menu.
1885 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
1886 BOOL sendMenuSelect )
1888 POPUPMENU *menu = MENU_GetMenu( hmenu );
1890 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
1892 if (menu && top_popup)
1898 if (menu->FocusedItem != NO_SELECTED_ITEM)
1900 item = &menu->items[menu->FocusedItem];
1901 if (!(item->fType & MF_POPUP) ||
1902 !(item->fState & MF_MOUSESELECT)) return;
1903 item->fState &= ~MF_MOUSESELECT;
1904 hsubmenu = item->hSubMenu;
1907 submenu = MENU_GetMenu( hsubmenu );
1908 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
1909 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
1910 DestroyWindow( submenu->hWnd );
1916 /***********************************************************************
1919 * Display the sub-menu of the selected item of this menu.
1920 * Return the handle of the submenu, or hmenu if no submenu to display.
1922 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
1923 BOOL selectFirst, UINT wFlags )
1930 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, selectFirst);
1932 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
1934 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
1936 item = &menu->items[menu->FocusedItem];
1937 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
1940 /* message must be sent before using item,
1941 because nearly everything may be changed by the application ! */
1943 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
1944 if (!(wFlags & TPM_NONOTIFY))
1945 SendMessageW( hwndOwner, WM_INITMENUPOPUP, (WPARAM)item->hSubMenu,
1946 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
1948 item = &menu->items[menu->FocusedItem];
1951 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
1952 if (!(item->fState & MF_HILITE))
1954 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
1955 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1957 SelectObject( hdc, hMenuFont);
1959 item->fState |= MF_HILITE;
1960 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
1961 ReleaseDC( menu->hWnd, hdc );
1963 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
1966 item->fState |= MF_MOUSESELECT;
1968 if (IS_SYSTEM_MENU(menu))
1970 MENU_InitSysMenuPopup(item->hSubMenu,
1971 GetWindowLongW( menu->hWnd, GWL_STYLE ),
1972 GetClassLongW( menu->hWnd, GCL_STYLE));
1974 NC_GetSysPopupPos( menu->hWnd, &rect );
1975 rect.top = rect.bottom;
1976 rect.right = GetSystemMetrics(SM_CXSIZE);
1977 rect.bottom = GetSystemMetrics(SM_CYSIZE);
1981 GetWindowRect( menu->hWnd, &rect );
1982 if (menu->wFlags & MF_POPUP)
1984 rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
1985 rect.top += item->rect.top;
1986 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
1987 rect.bottom = item->rect.top - item->rect.bottom;
1991 rect.left += item->rect.left;
1992 rect.top += item->rect.bottom;
1993 rect.right = item->rect.right - item->rect.left;
1994 rect.bottom = item->rect.bottom - item->rect.top;
1998 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
1999 rect.left, rect.top, rect.right, rect.bottom );
2001 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2002 return item->hSubMenu;
2007 /**********************************************************************
2010 HWND MENU_IsMenuActive(void)
2015 /***********************************************************************
2018 * Walks menu chain trying to find a menu pt maps to.
2020 static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2022 POPUPMENU *menu = MENU_GetMenu( hMenu );
2023 UINT item = menu->FocusedItem;
2026 /* try subpopup first (if any) */
2027 ret = (item != NO_SELECTED_ITEM &&
2028 (menu->items[item].fType & MF_POPUP) &&
2029 (menu->items[item].fState & MF_MOUSESELECT))
2030 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
2032 if (!ret) /* check the current window (avoiding WM_HITTEST) */
2034 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2035 if( menu->wFlags & MF_POPUP )
2037 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2039 else if (ht == HTSYSMENU)
2040 ret = get_win_sys_menu( menu->hWnd );
2041 else if (ht == HTMENU)
2042 ret = GetMenu( menu->hWnd );
2047 /***********************************************************************
2048 * MENU_ExecFocusedItem
2050 * Execute a menu item (for instance when user pressed Enter).
2051 * Return the wID of the executed item. Otherwise, -1 indicating
2052 * that no menu item was executed;
2053 * Have to receive the flags for the TrackPopupMenu options to avoid
2054 * sending unwanted message.
2057 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2060 POPUPMENU *menu = MENU_GetMenu( hMenu );
2062 TRACE("%p hmenu=%p\n", pmt, hMenu);
2064 if (!menu || !menu->nItems ||
2065 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2067 item = &menu->items[menu->FocusedItem];
2069 TRACE("%p %08x %p\n", hMenu, item->wID, item->hSubMenu);
2071 if (!(item->fType & MF_POPUP))
2073 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2075 /* If TPM_RETURNCMD is set you return the id, but
2076 do not send a message to the owner */
2077 if(!(wFlags & TPM_RETURNCMD))
2079 if( menu->wFlags & MF_SYSMENU )
2080 PostMessageW( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2081 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2083 PostMessageW( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2089 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2094 /***********************************************************************
2095 * MENU_SwitchTracking
2097 * Helper function for menu navigation routines.
2099 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2101 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2102 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2104 TRACE("%p hmenu=%p 0x%04x\n", pmt, hPtMenu, id);
2106 if( pmt->hTopMenu != hPtMenu &&
2107 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2109 /* both are top level menus (system and menu-bar) */
2110 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2111 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2112 pmt->hTopMenu = hPtMenu;
2114 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2115 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2119 /***********************************************************************
2122 * Return TRUE if we can go on with menu tracking.
2124 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2126 TRACE("%p hPtMenu=%p\n", pmt, hPtMenu);
2131 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2134 if( IS_SYSTEM_MENU(ptmenu) )
2135 item = ptmenu->items;
2137 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2141 if( ptmenu->FocusedItem != id )
2142 MENU_SwitchTracking( pmt, hPtMenu, id );
2144 /* If the popup menu is not already "popped" */
2145 if(!(item->fState & MF_MOUSESELECT ))
2147 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2152 /* Else the click was on the menu bar, finish the tracking */
2157 /***********************************************************************
2160 * Return the value of MENU_ExecFocusedItem if
2161 * the selected item was not a popup. Else open the popup.
2162 * A -1 return value indicates that we go on with menu tracking.
2165 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2167 TRACE("%p hmenu=%p\n", pmt, hPtMenu);
2172 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2175 if( IS_SYSTEM_MENU(ptmenu) )
2176 item = ptmenu->items;
2178 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2180 if( item && (ptmenu->FocusedItem == id ))
2182 if( !(item->fType & MF_POPUP) )
2183 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2185 /* If we are dealing with the top-level menu */
2186 /* and this is a click on an already "popped" item: */
2187 /* Stop the menu tracking and close the opened submenus */
2188 if((pmt->hTopMenu == hPtMenu) && ptmenu->bTimeToHide)
2191 ptmenu->bTimeToHide = TRUE;
2197 /***********************************************************************
2200 * Return TRUE if we can go on with menu tracking.
2202 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2204 UINT id = NO_SELECTED_ITEM;
2205 POPUPMENU *ptmenu = NULL;
2209 ptmenu = MENU_GetMenu( hPtMenu );
2210 if( IS_SYSTEM_MENU(ptmenu) )
2213 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2216 if( id == NO_SELECTED_ITEM )
2218 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2219 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2222 else if( ptmenu->FocusedItem != id )
2224 MENU_SwitchTracking( pmt, hPtMenu, id );
2225 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2231 /***********************************************************************
2234 static void MENU_SetCapture( HWND hwnd )
2238 SERVER_START_REQ( set_capture_window )
2241 req->flags = CAPTURE_MENU;
2242 if (!wine_server_call_err( req ))
2244 previous = reply->previous;
2245 hwnd = reply->full_handle;
2250 if (previous && previous != hwnd)
2251 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
2255 /***********************************************************************
2258 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2260 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2262 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2264 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2265 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2267 MDINEXTMENU next_menu;
2272 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2273 next_menu.hmenuNext = 0;
2274 next_menu.hwndNext = 0;
2275 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2277 TRACE("%p [%p] -> %p [%p]\n",
2278 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2280 if (!next_menu.hmenuNext || !next_menu.hwndNext)
2282 DWORD style = GetWindowLongW( pmt->hOwnerWnd, GWL_STYLE );
2283 hNewWnd = pmt->hOwnerWnd;
2284 if( IS_SYSTEM_MENU(menu) )
2286 /* switch to the menu bar */
2288 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2292 menu = MENU_GetMenu( hNewMenu );
2293 id = menu->nItems - 1;
2296 else if (style & WS_SYSMENU )
2298 /* switch to the system menu */
2299 hNewMenu = get_win_sys_menu( hNewWnd );
2303 else /* application returned a new menu to switch to */
2305 hNewMenu = next_menu.hmenuNext;
2306 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2308 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2310 DWORD style = GetWindowLongW( hNewWnd, GWL_STYLE );
2312 if (style & WS_SYSMENU &&
2313 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2315 /* get the real system menu */
2316 hNewMenu = get_win_sys_menu(hNewWnd);
2318 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2320 /* FIXME: Not sure what to do here;
2321 * perhaps try to track hNewMenu as a popup? */
2323 TRACE(" -- got confused.\n");
2330 if( hNewMenu != pmt->hTopMenu )
2332 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2334 if( pmt->hCurrentMenu != pmt->hTopMenu )
2335 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2338 if( hNewWnd != pmt->hOwnerWnd )
2340 pmt->hOwnerWnd = hNewWnd;
2341 MENU_SetCapture( pmt->hOwnerWnd );
2344 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2345 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2352 /***********************************************************************
2355 * The idea is not to show the popup if the next input message is
2356 * going to hide it anyway.
2358 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2362 msg.hwnd = pmt->hOwnerWnd;
2364 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2365 pmt->trackFlags |= TF_SKIPREMOVE;
2370 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2371 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2373 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2374 PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2375 if( msg.message == WM_KEYDOWN &&
2376 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2378 pmt->trackFlags |= TF_SUSPENDPOPUP;
2385 /* failures go through this */
2386 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2390 /***********************************************************************
2393 * Handle a VK_ESCAPE key event in a menu.
2395 static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2397 BOOL bEndMenu = TRUE;
2399 if (pmt->hCurrentMenu != pmt->hTopMenu)
2401 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2403 if (menu->wFlags & MF_POPUP)
2405 HMENU hmenutmp, hmenuprev;
2407 hmenuprev = hmenutmp = pmt->hTopMenu;
2409 /* close topmost popup */
2410 while (hmenutmp != pmt->hCurrentMenu)
2412 hmenuprev = hmenutmp;
2413 hmenutmp = MENU_GetSubPopup( hmenuprev );
2416 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2417 pmt->hCurrentMenu = hmenuprev;
2425 /***********************************************************************
2428 * Handle a VK_LEFT key event in a menu.
2430 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2433 HMENU hmenutmp, hmenuprev;
2436 hmenuprev = hmenutmp = pmt->hTopMenu;
2437 menu = MENU_GetMenu( hmenutmp );
2439 /* Try to move 1 column left (if possible) */
2440 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2441 NO_SELECTED_ITEM ) {
2443 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2448 /* close topmost popup */
2449 while (hmenutmp != pmt->hCurrentMenu)
2451 hmenuprev = hmenutmp;
2452 hmenutmp = MENU_GetSubPopup( hmenuprev );
2455 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2456 pmt->hCurrentMenu = hmenuprev;
2458 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2460 /* move menu bar selection if no more popups are left */
2462 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2463 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2465 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2467 /* A sublevel menu was displayed - display the next one
2468 * unless there is another displacement coming up */
2470 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2471 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2472 pmt->hTopMenu, TRUE, wFlags);
2478 /***********************************************************************
2481 * Handle a VK_RIGHT key event in a menu.
2483 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2486 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2489 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2491 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->items[0].text),
2492 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2494 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2496 /* If already displaying a popup, try to display sub-popup */
2498 hmenutmp = pmt->hCurrentMenu;
2499 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2501 /* if subpopup was displayed then we are done */
2502 if (hmenutmp != pmt->hCurrentMenu) return;
2505 /* Check to see if there's another column */
2506 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2507 NO_SELECTED_ITEM ) {
2508 TRACE("Going to %d.\n", nextcol );
2509 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2514 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2516 if( pmt->hCurrentMenu != pmt->hTopMenu )
2518 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2519 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2520 } else hmenutmp = 0;
2522 /* try to move to the next item */
2523 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2524 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2526 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2527 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2528 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2529 pmt->hTopMenu, TRUE, wFlags);
2533 /***********************************************************************
2536 * Menu tracking code.
2538 static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2539 HWND hwnd, const RECT *lprect )
2544 INT executedMenuId = -1;
2546 BOOL enterIdleSent = FALSE;
2549 mt.hCurrentMenu = hmenu;
2550 mt.hTopMenu = hmenu;
2551 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2555 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p (%ld,%ld)-(%ld,%ld)\n",
2556 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2557 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2560 if (!(menu = MENU_GetMenu( hmenu )))
2562 WARN("Invalid menu handle %p\n", hmenu);
2563 SetLastError(ERROR_INVALID_MENU_HANDLE);
2567 if (wFlags & TPM_BUTTONDOWN)
2569 /* Get the result in order to start the tracking or not */
2570 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2571 fEndMenu = !fRemove;
2574 if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
2576 MENU_SetCapture( mt.hOwnerWnd );
2580 menu = MENU_GetMenu( mt.hCurrentMenu );
2581 if (!menu) /* sometimes happens if I do a window manager close */
2584 /* we have to keep the message in the queue until it's
2585 * clear that menu loop is not over yet. */
2589 if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
2591 if (!CallMsgFilterW( &msg, MSGF_MENU )) break;
2592 /* remove the message from the queue */
2593 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2599 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2600 enterIdleSent = TRUE;
2601 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2607 /* check if EndMenu() tried to cancel us, by posting this message */
2608 if(msg.message == WM_CANCELMODE)
2610 /* we are now out of the loop */
2613 /* remove the message from the queue */
2614 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2616 /* break out of internal loop, ala ESCAPE */
2620 TranslateMessage( &msg );
2623 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2624 enterIdleSent=FALSE;
2627 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2630 * Use the mouse coordinates in lParam instead of those in the MSG
2631 * struct to properly handle synthetic messages. They are already
2632 * in screen coordinates.
2634 mt.pt.x = (short)LOWORD(msg.lParam);
2635 mt.pt.y = (short)HIWORD(msg.lParam);
2637 /* Find a menu for this mouse event */
2638 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2642 /* no WM_NC... messages in captured state */
2644 case WM_RBUTTONDBLCLK:
2645 case WM_RBUTTONDOWN:
2646 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2648 case WM_LBUTTONDBLCLK:
2649 case WM_LBUTTONDOWN:
2650 /* If the message belongs to the menu, removes it from the queue */
2651 /* Else, end menu tracking */
2652 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2653 fEndMenu = !fRemove;
2657 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2660 /* Check if a menu was selected by the mouse */
2663 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2665 /* End the loop if executedMenuId is an item ID */
2666 /* or if the job was done (executedMenuId = 0). */
2667 fEndMenu = fRemove = (executedMenuId != -1);
2669 /* No menu was selected by the mouse */
2670 /* if the function was called by TrackPopupMenu, continue
2671 with the menu tracking. If not, stop it */
2673 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2678 /* the selected menu item must be changed every time */
2679 /* the mouse moves. */
2682 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2684 } /* switch(msg.message) - mouse */
2686 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2688 fRemove = TRUE; /* Keyboard messages are always removed */
2701 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2702 NO_SELECTED_ITEM, FALSE, 0 );
2705 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2706 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2709 case VK_DOWN: /* If on menu bar, pull-down the menu */
2711 menu = MENU_GetMenu( mt.hCurrentMenu );
2712 if (!(menu->wFlags & MF_POPUP))
2713 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2714 else /* otherwise try to move selection */
2715 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2719 MENU_KeyLeft( &mt, wFlags );
2723 MENU_KeyRight( &mt, wFlags );
2727 fEndMenu = MENU_KeyEscape(&mt, wFlags);
2733 hi.cbSize = sizeof(HELPINFO);
2734 hi.iContextType = HELPINFO_MENUITEM;
2735 if (menu->FocusedItem == NO_SELECTED_ITEM)
2738 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2739 hi.hItemHandle = hmenu;
2740 hi.dwContextId = menu->dwContextHelpID;
2741 hi.MousePos = msg.pt;
2742 SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
2749 break; /* WM_KEYDOWN */
2756 if (msg.wParam == '\r' || msg.wParam == ' ')
2758 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2759 fEndMenu = (executedMenuId != -1);
2764 /* Hack to avoid control chars. */
2765 /* We will find a better way real soon... */
2766 if (msg.wParam < 32) break;
2768 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
2769 LOWORD(msg.wParam), FALSE );
2770 if (pos == (UINT)-2) fEndMenu = TRUE;
2771 else if (pos == (UINT)-1) MessageBeep(0);
2774 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2776 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2777 fEndMenu = (executedMenuId != -1);
2781 } /* switch(msg.message) - kbd */
2785 DispatchMessageW( &msg );
2788 if (!fEndMenu) fRemove = TRUE;
2790 /* finally remove message from the queue */
2792 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2793 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
2794 else mt.trackFlags &= ~TF_SKIPREMOVE;
2797 MENU_SetCapture(0); /* release the capture */
2799 /* If dropdown is still painted and the close box is clicked on
2800 then the menu will be destroyed as part of the DispatchMessage above.
2801 This will then invalidate the menu handle in mt.hTopMenu. We should
2802 check for this first. */
2803 if( IsMenu( mt.hTopMenu ) )
2805 menu = MENU_GetMenu( mt.hTopMenu );
2807 if( IsWindow( mt.hOwnerWnd ) )
2809 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2811 if (menu && menu->wFlags & MF_POPUP)
2813 DestroyWindow( menu->hWnd );
2816 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2817 SendMessageW( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2820 /* Reset the variable for hiding menu */
2821 if( menu ) menu->bTimeToHide = FALSE;
2824 /* The return value is only used by TrackPopupMenu */
2825 if (!(wFlags & TPM_RETURNCMD)) return TRUE;
2826 if (executedMenuId == -1) executedMenuId = 0;
2827 return executedMenuId;
2830 /***********************************************************************
2833 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
2837 TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
2841 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2842 if (!(wFlags & TPM_NONOTIFY))
2843 SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2845 SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
2847 if (!(wFlags & TPM_NONOTIFY))
2849 SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
2850 /* If an app changed/recreated menu bar entries in WM_INITMENU
2851 * menu sizes will be recalculated once the menu created/shown.
2855 /* This makes the menus of applications built with Delphi work.
2856 * It also enables menus to be displayed in more than one window,
2857 * but there are some bugs left that need to be fixed in this case.
2859 if ((menu = MENU_GetMenu( hMenu ))) menu->hWnd = hWnd;
2863 /***********************************************************************
2866 static BOOL MENU_ExitTracking(HWND hWnd)
2868 TRACE("hwnd=%p\n", hWnd);
2870 SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 );
2876 /***********************************************************************
2877 * MENU_TrackMouseMenuBar
2879 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2881 void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
2883 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
2884 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2886 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
2890 /* map point to parent client coordinates */
2891 HWND parent = GetAncestor( hWnd, GA_PARENT );
2892 if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );
2894 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2895 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
2896 MENU_ExitTracking(hWnd);
2901 /***********************************************************************
2902 * MENU_TrackKbdMenuBar
2904 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2906 void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar)
2908 UINT uItem = NO_SELECTED_ITEM;
2910 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2912 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
2914 /* find window that has a menu */
2916 while (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)
2917 if (!(hwnd = GetParent( hwnd ))) return;
2919 /* check if we have to track a system menu */
2921 hTrackMenu = GetMenu( hwnd );
2922 if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' )
2924 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
2925 hTrackMenu = get_win_sys_menu( hwnd );
2927 wParam |= HTSYSMENU; /* prevent item lookup */
2930 if (!IsMenu( hTrackMenu )) return;
2932 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
2934 if( wChar && wChar != ' ' )
2936 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) );
2937 if ( uItem >= (UINT)(-2) )
2939 if( uItem == (UINT)(-1) ) MessageBeep(0);
2940 /* schedule end of menu tracking */
2941 wFlags |= TF_ENDMENU;
2946 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
2948 if (wParam & HTSYSMENU)
2950 /* prevent sysmenu activation for managed windows on Alt down/up */
2951 if (GetPropA( hwnd, "__wine_x11_managed" ))
2952 wFlags |= TF_ENDMENU; /* schedule end of menu tracking */
2956 if( uItem == NO_SELECTED_ITEM )
2957 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
2959 PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
2963 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
2964 MENU_ExitTracking( hwnd );
2968 /**********************************************************************
2969 * TrackPopupMenu (USER32.@)
2971 * Like the win32 API, the function return the command ID only if the
2972 * flag TPM_RETURNCMD is on.
2975 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
2976 INT nReserved, HWND hWnd, const RECT *lpRect )
2980 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
2982 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2983 if (!(wFlags & TPM_NONOTIFY))
2984 SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0);
2986 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
2987 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
2988 MENU_ExitTracking(hWnd);
2993 /**********************************************************************
2994 * TrackPopupMenuEx (USER32.@)
2996 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
2997 HWND hWnd, LPTPMPARAMS lpTpm )
2999 FIXME("not fully implemented\n" );
3000 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3001 lpTpm ? &lpTpm->rcExclude : NULL );
3004 /***********************************************************************
3007 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3009 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3011 TRACE("hwnd=%p msg=0x%04x wp=0x%04x lp=0x%08lx\n", hwnd, message, wParam, lParam);
3017 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3018 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3022 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3023 return MA_NOACTIVATE;
3028 BeginPaint( hwnd, &ps );
3029 MENU_DrawPopupMenu( hwnd, ps.hdc,
3030 (HMENU)GetWindowLongW( hwnd, 0 ) );
3031 EndPaint( hwnd, &ps );
3038 /* zero out global pointer in case resident popup window was destroyed. */
3039 if (hwnd == top_popup) top_popup = 0;
3046 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
3049 SetWindowLongW( hwnd, 0, 0 );
3052 case MM_SETMENUHANDLE:
3053 SetWindowLongW( hwnd, 0, wParam );
3056 case MM_GETMENUHANDLE:
3057 return GetWindowLongW( hwnd, 0 );
3060 return DefWindowProcW( hwnd, message, wParam, lParam );
3066 /***********************************************************************
3067 * MENU_GetMenuBarHeight
3069 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3071 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3072 INT orgX, INT orgY )
3078 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
3080 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3082 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3083 SelectObject( hdc, hMenuFont);
3084 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3085 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3086 ReleaseDC( hwnd, hdc );
3087 return lppop->Height;
3091 /*******************************************************************
3092 * ChangeMenuA (USER32.@)
3094 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3095 UINT id, UINT flags )
3097 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3098 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3100 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3101 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3103 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3104 flags & MF_BYPOSITION ? pos : id,
3105 flags & ~MF_REMOVE );
3106 /* Default: MF_INSERT */
3107 return InsertMenuA( hMenu, pos, flags, id, data );
3111 /*******************************************************************
3112 * ChangeMenuW (USER32.@)
3114 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3115 UINT id, UINT flags )
3117 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
3118 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3120 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3121 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3123 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3124 flags & MF_BYPOSITION ? pos : id,
3125 flags & ~MF_REMOVE );
3126 /* Default: MF_INSERT */
3127 return InsertMenuW( hMenu, pos, flags, id, data );
3131 /*******************************************************************
3132 * CheckMenuItem (USER32.@)
3134 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3139 TRACE("menu=%p id=%04x flags=%04x\n", hMenu, id, flags );
3140 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3141 ret = item->fState & MF_CHECKED;
3142 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3143 else item->fState &= ~MF_CHECKED;
3148 /**********************************************************************
3149 * EnableMenuItem (USER32.@)
3151 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3157 TRACE("(%p, %04x, %04x) !\n", hMenu, wItemID, wFlags);
3159 /* Get the Popupmenu to access the owner menu */
3160 if (!(menu = MENU_GetMenu(hMenu)))
3163 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3166 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3167 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3169 /* If the close item in the system menu change update the close button */
3170 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3172 if (menu->hSysMenuOwner != 0)
3174 POPUPMENU* parentMenu;
3176 /* Get the parent menu to access*/
3177 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3180 /* Refresh the frame to reflect the change*/
3181 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3182 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3190 /*******************************************************************
3191 * GetMenuStringA (USER32.@)
3193 INT WINAPI GetMenuStringA(
3194 HMENU hMenu, /* [in] menuhandle */
3195 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3196 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3197 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3198 UINT wFlags /* [in] MF_ flags */
3202 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3203 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3204 if (!IS_STRING_ITEM(item->fType)) return 0;
3205 if (!str || !nMaxSiz) return strlenW(item->text);
3207 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3209 TRACE("returning '%s'\n", str );
3214 /*******************************************************************
3215 * GetMenuStringW (USER32.@)
3217 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3218 LPWSTR str, INT nMaxSiz, UINT wFlags )
3222 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3223 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3224 if (!IS_STRING_ITEM(item->fType)) return 0;
3225 if (!str || !nMaxSiz) return strlenW(item->text);
3227 lstrcpynW( str, item->text, nMaxSiz );
3228 return strlenW(str);
3232 /**********************************************************************
3233 * HiliteMenuItem (USER32.@)
3235 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3239 TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
3240 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3241 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3242 if (menu->FocusedItem == wItemID) return TRUE;
3243 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3244 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3249 /**********************************************************************
3250 * GetMenuState (USER32.@)
3252 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3255 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, wItemID, wFlags);
3256 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3257 debug_print_menuitem (" item: ", item, "");
3258 if (item->fType & MF_POPUP)
3260 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3261 if (!menu) return -1;
3262 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3266 /* We used to (from way back then) mask the result to 0xff. */
3267 /* I don't know why and it seems wrong as the documented */
3268 /* return flag MF_SEPARATOR is outside that mask. */
3269 return (item->fType | item->fState);
3274 /**********************************************************************
3275 * GetMenuItemCount (USER32.@)
3277 INT WINAPI GetMenuItemCount( HMENU hMenu )
3279 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3280 if (!menu) return -1;
3281 TRACE("(%p) returning %d\n", hMenu, menu->nItems );
3282 return menu->nItems;
3286 /**********************************************************************
3287 * GetMenuItemID (USER32.@)
3289 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3293 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
3294 if (lpmi->fType & MF_POPUP) return -1;
3300 /*******************************************************************
3301 * InsertMenuW (USER32.@)
3303 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3304 UINT_PTR id, LPCWSTR str )
3308 if (IS_STRING_ITEM(flags) && str)
3309 TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3310 hMenu, pos, flags, id, debugstr_w(str) );
3311 else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %08lx (not a string)\n",
3312 hMenu, pos, flags, id, (DWORD)str );
3314 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3316 if (!(MENU_SetItemData( item, flags, id, str )))
3318 RemoveMenu( hMenu, pos, flags );
3322 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3323 (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
3325 item->hCheckBit = item->hUnCheckBit = 0;
3330 /*******************************************************************
3331 * InsertMenuA (USER32.@)
3333 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3334 UINT_PTR id, LPCSTR str )
3338 if (IS_STRING_ITEM(flags) && str)
3340 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3341 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3344 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3345 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3346 HeapFree( GetProcessHeap(), 0, newstr );
3350 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3354 /*******************************************************************
3355 * AppendMenuA (USER32.@)
3357 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3358 UINT_PTR id, LPCSTR data )
3360 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3364 /*******************************************************************
3365 * AppendMenuW (USER32.@)
3367 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3368 UINT_PTR id, LPCWSTR data )
3370 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3374 /**********************************************************************
3375 * RemoveMenu (USER32.@)
3377 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3382 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3383 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3384 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3388 MENU_FreeItemData( item );
3390 if (--menu->nItems == 0)
3392 HeapFree( GetProcessHeap(), 0, menu->items );
3397 while(nPos < menu->nItems)
3403 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3404 menu->nItems * sizeof(MENUITEM) );
3410 /**********************************************************************
3411 * DeleteMenu (USER32.@)
3413 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3415 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3416 if (!item) return FALSE;
3417 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3418 /* nPos is now the position of the item */
3419 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3424 /*******************************************************************
3425 * ModifyMenuW (USER32.@)
3427 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3428 UINT_PTR id, LPCWSTR str )
3432 if (IS_STRING_ITEM(flags))
3434 TRACE("%p %d %04x %04x %s\n", hMenu, pos, flags, id, debugstr_w(str) );
3438 TRACE("%p %d %04x %04x %08lx\n", hMenu, pos, flags, id, (DWORD)str );
3441 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3442 return MENU_SetItemData( item, flags, id, str );
3446 /*******************************************************************
3447 * ModifyMenuA (USER32.@)
3449 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3450 UINT_PTR id, LPCSTR str )
3454 if (IS_STRING_ITEM(flags) && str)
3456 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3457 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3460 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3461 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3462 HeapFree( GetProcessHeap(), 0, newstr );
3466 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3470 /**********************************************************************
3471 * CreatePopupMenu (USER32.@)
3473 HMENU WINAPI CreatePopupMenu(void)
3478 if (!(hmenu = CreateMenu())) return 0;
3479 menu = MENU_GetMenu( hmenu );
3480 menu->wFlags |= MF_POPUP;
3481 menu->bTimeToHide = FALSE;
3486 /**********************************************************************
3487 * GetMenuCheckMarkDimensions (USER.417)
3488 * GetMenuCheckMarkDimensions (USER32.@)
3490 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3492 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3496 /**********************************************************************
3497 * SetMenuItemBitmaps (USER32.@)
3499 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3500 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3503 TRACE("(%p, %04x, %04x, %p, %p)\n",
3504 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3505 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3507 if (!hNewCheck && !hNewUnCheck)
3509 item->fState &= ~MF_USECHECKBITMAPS;
3511 else /* Install new bitmaps */
3513 item->hCheckBit = hNewCheck;
3514 item->hUnCheckBit = hNewUnCheck;
3515 item->fState |= MF_USECHECKBITMAPS;
3521 /**********************************************************************
3522 * CreateMenu (USER32.@)
3524 HMENU WINAPI CreateMenu(void)
3528 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3529 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3531 ZeroMemory(menu, sizeof(POPUPMENU));
3532 menu->wMagic = MENU_MAGIC;
3533 menu->FocusedItem = NO_SELECTED_ITEM;
3534 menu->bTimeToHide = FALSE;
3536 TRACE("return %p\n", hMenu );
3542 /**********************************************************************
3543 * DestroyMenu (USER32.@)
3545 BOOL WINAPI DestroyMenu( HMENU hMenu )
3547 TRACE("(%p)\n", hMenu);
3549 /* Silently ignore attempts to destroy default system popup */
3551 if (hMenu && hMenu != MENU_DefSysPopup)
3553 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3555 if (!lppop) return FALSE;
3557 lppop->wMagic = 0; /* Mark it as destroyed */
3559 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
3561 DestroyWindow( lppop->hWnd );
3565 if (lppop->items) /* recursively destroy submenus */
3568 MENUITEM *item = lppop->items;
3569 for (i = lppop->nItems; i > 0; i--, item++)
3571 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3572 MENU_FreeItemData( item );
3574 HeapFree( GetProcessHeap(), 0, lppop->items );
3576 USER_HEAP_FREE( hMenu );
3578 return (hMenu != MENU_DefSysPopup);
3582 /**********************************************************************
3583 * GetSystemMenu (USER32.@)
3585 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3587 WND *wndPtr = WIN_GetPtr( hWnd );
3590 if (wndPtr == WND_OTHER_PROCESS)
3592 if (IsWindow( hWnd )) FIXME( "not supported on other process window %p\n", hWnd );
3596 if( wndPtr->hSysMenu )
3600 DestroyMenu(wndPtr->hSysMenu);
3601 wndPtr->hSysMenu = 0;
3605 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3608 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3609 menu->items[0].hSubMenu = MENU_CopySysPopup();
3613 WARN("Current sys-menu (%p) of wnd %p is broken\n",
3614 wndPtr->hSysMenu, hWnd);
3615 wndPtr->hSysMenu = 0;
3620 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3621 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3623 if( wndPtr->hSysMenu )
3626 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3628 /* Store the dummy sysmenu handle to facilitate the refresh */
3629 /* of the close button if the SC_CLOSE item change */
3630 menu = MENU_GetMenu(retvalue);
3632 menu->hSysMenuOwner = wndPtr->hSysMenu;
3634 WIN_ReleasePtr( wndPtr );
3636 return bRevert ? 0 : retvalue;
3640 /*******************************************************************
3641 * SetSystemMenu (USER32.@)
3643 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3645 WND *wndPtr = WIN_GetPtr( hwnd );
3647 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
3649 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3650 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3651 WIN_ReleasePtr( wndPtr );
3658 /**********************************************************************
3659 * GetMenu (USER32.@)
3661 HMENU WINAPI GetMenu( HWND hWnd )
3663 HMENU retvalue = (HMENU)GetWindowLongPtrW( hWnd, GWLP_ID );
3664 TRACE("for %p returning %p\n", hWnd, retvalue);
3669 /**********************************************************************
3672 * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
3673 * SetWindowPos call that would result if SetMenu were called directly.
3675 BOOL MENU_SetMenu( HWND hWnd, HMENU hMenu )
3677 TRACE("(%p, %p);\n", hWnd, hMenu);
3679 if (hMenu && !IsMenu(hMenu))
3681 WARN("hMenu %p is not a menu handle\n", hMenu);
3684 if (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
3686 hWnd = WIN_GetFullHandle( hWnd );
3687 if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */
3693 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
3695 lpmenu->hWnd = hWnd;
3696 lpmenu->Height = 0; /* Make sure we recalculate the size */
3698 SetWindowLongPtrW( hWnd, GWLP_ID, (LONG_PTR)hMenu );
3703 /**********************************************************************
3704 * SetMenu (USER32.@)
3706 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
3708 if(!MENU_SetMenu(hWnd, hMenu))
3711 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3712 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3717 /**********************************************************************
3718 * GetSubMenu (USER32.@)
3720 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
3724 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3725 if (!(lpmi->fType & MF_POPUP)) return 0;
3726 return lpmi->hSubMenu;
3730 /**********************************************************************
3731 * DrawMenuBar (USER32.@)
3733 BOOL WINAPI DrawMenuBar( HWND hWnd )
3736 HMENU hMenu = GetMenu(hWnd);
3738 if (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
3739 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
3741 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
3742 lppop->hwndOwner = hWnd;
3743 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3744 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3748 /***********************************************************************
3749 * DrawMenuBarTemp (USER32.@)
3753 * called by W98SE desk.cpl Control Panel Applet
3755 * Not 100% sure about the param names, but close.
3757 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont)
3764 hMenu = GetMenu(hwnd);
3769 lppop = MENU_GetMenu( hMenu );
3770 if (lppop == NULL || lprect == NULL)
3772 retvalue = GetSystemMetrics(SM_CYMENU);
3776 TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont);
3778 hfontOld = SelectObject( hDC, hFont);
3780 if (lppop->Height == 0)
3781 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
3783 lprect->bottom = lprect->top + lppop->Height;
3785 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
3787 SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE));
3788 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
3789 LineTo( hDC, lprect->right, lprect->bottom );
3791 if (lppop->nItems == 0)
3793 retvalue = GetSystemMetrics(SM_CYMENU);
3797 for (i = 0; i < lppop->nItems; i++)
3799 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
3800 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
3802 retvalue = lppop->Height;
3805 if (hfontOld) SelectObject (hDC, hfontOld);
3809 /***********************************************************************
3810 * EndMenu (USER.187)
3811 * EndMenu (USER32.@)
3813 void WINAPI EndMenu(void)
3815 /* if we are in the menu code, and it is active */
3816 if (!fEndMenu && top_popup)
3818 /* terminate the menu handling code */
3821 /* needs to be posted to wakeup the internal menu handler */
3822 /* which will now terminate the menu, in the event that */
3823 /* the main window was minimized, or lost focus, so we */
3824 /* don't end up with an orphaned menu */
3825 PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
3830 /***********************************************************************
3831 * LookupMenuHandle (USER.217)
3833 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
3835 HMENU hmenu32 = HMENU_32(hmenu);
3837 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
3838 else return HMENU_16(hmenu32);
3842 /**********************************************************************
3843 * LoadMenu (USER.150)
3845 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
3851 if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
3852 if (!name) return 0;
3854 instance = GetExePtr( instance );
3855 if (!(hRsrc = FindResource16( instance, name, (LPSTR)RT_MENU ))) return 0;
3856 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
3857 hMenu = LoadMenuIndirect16(LockResource16(handle));
3858 FreeResource16( handle );
3863 /*****************************************************************
3864 * LoadMenuA (USER32.@)
3866 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
3868 HRSRC hrsrc = FindResourceA( instance, name, (LPSTR)RT_MENU );
3869 if (!hrsrc) return 0;
3870 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
3874 /*****************************************************************
3875 * LoadMenuW (USER32.@)
3877 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
3879 HRSRC hrsrc = FindResourceW( instance, name, (LPWSTR)RT_MENU );
3880 if (!hrsrc) return 0;
3881 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
3885 /**********************************************************************
3886 * LoadMenuIndirect (USER.220)
3888 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
3891 WORD version, offset;
3892 LPCSTR p = (LPCSTR)template;
3894 TRACE("(%p)\n", template );
3895 version = GET_WORD(p);
3899 WARN("version must be 0 for Win16\n" );
3902 offset = GET_WORD(p);
3903 p += sizeof(WORD) + offset;
3904 if (!(hMenu = CreateMenu())) return 0;
3905 if (!MENU_ParseResource( p, hMenu, FALSE ))
3907 DestroyMenu( hMenu );
3910 return HMENU_16(hMenu);
3914 /**********************************************************************
3915 * LoadMenuIndirectW (USER32.@)
3917 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
3920 WORD version, offset;
3921 LPCSTR p = (LPCSTR)template;
3923 version = GET_WORD(p);
3925 TRACE("%p, ver %d\n", template, version );
3928 case 0: /* standard format is version of 0 */
3929 offset = GET_WORD(p);
3930 p += sizeof(WORD) + offset;
3931 if (!(hMenu = CreateMenu())) return 0;
3932 if (!MENU_ParseResource( p, hMenu, TRUE ))
3934 DestroyMenu( hMenu );
3938 case 1: /* extended format is version of 1 */
3939 offset = GET_WORD(p);
3940 p += sizeof(WORD) + offset;
3941 if (!(hMenu = CreateMenu())) return 0;
3942 if (!MENUEX_ParseResource( p, hMenu))
3944 DestroyMenu( hMenu );
3949 ERR("version %d not supported.\n", version);
3955 /**********************************************************************
3956 * LoadMenuIndirectA (USER32.@)
3958 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
3960 return LoadMenuIndirectW( template );
3964 /**********************************************************************
3967 BOOL WINAPI IsMenu(HMENU hmenu)
3969 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
3970 return menu != NULL;
3973 /**********************************************************************
3974 * GetMenuItemInfo_common
3977 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
3978 LPMENUITEMINFOW lpmii, BOOL unicode)
3980 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
3982 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
3987 if (lpmii->fMask & MIIM_TYPE) {
3988 lpmii->fType = menu->fType;
3989 switch (MENU_ITEM_TYPE(menu->fType)) {
3991 break; /* will be done below */
3994 lpmii->dwTypeData = menu->text;
4001 /* copy the text string */
4002 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4003 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4008 len = strlenW(menu->text);
4009 if(lpmii->dwTypeData && lpmii->cch)
4010 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4014 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4015 if(lpmii->dwTypeData && lpmii->cch)
4016 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4017 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4018 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4020 /* if we've copied a substring we return its length */
4021 if(lpmii->dwTypeData && lpmii->cch)
4023 if (lpmii->cch <= len) lpmii->cch--;
4025 else /* return length of string */
4029 if (lpmii->fMask & MIIM_FTYPE)
4030 lpmii->fType = menu->fType;
4032 if (lpmii->fMask & MIIM_BITMAP)
4033 lpmii->hbmpItem = menu->hbmpItem;
4035 if (lpmii->fMask & MIIM_STATE)
4036 lpmii->fState = menu->fState;
4038 if (lpmii->fMask & MIIM_ID)
4039 lpmii->wID = menu->wID;
4041 if (lpmii->fMask & MIIM_SUBMENU)
4042 lpmii->hSubMenu = menu->hSubMenu;
4044 if (lpmii->fMask & MIIM_CHECKMARKS) {
4045 lpmii->hbmpChecked = menu->hCheckBit;
4046 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4048 if (lpmii->fMask & MIIM_DATA)
4049 lpmii->dwItemData = menu->dwItemData;
4054 /**********************************************************************
4055 * GetMenuItemInfoA (USER32.@)
4057 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4058 LPMENUITEMINFOA lpmii)
4060 return GetMenuItemInfo_common (hmenu, item, bypos,
4061 (LPMENUITEMINFOW)lpmii, FALSE);
4064 /**********************************************************************
4065 * GetMenuItemInfoW (USER32.@)
4067 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4068 LPMENUITEMINFOW lpmii)
4070 return GetMenuItemInfo_common (hmenu, item, bypos,
4075 /* set a menu item text from a ASCII or Unicode string */
4076 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4081 menu->fType |= MF_SEPARATOR;
4085 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4086 strcpyW( menu->text, text );
4090 LPCSTR str = (LPCSTR)text;
4091 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4092 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4093 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4098 /**********************************************************************
4099 * SetMenuItemInfo_common
4102 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4103 const MENUITEMINFOW *lpmii,
4106 if (!menu) return FALSE;
4108 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4110 if (lpmii->fMask & MIIM_TYPE ) {
4111 /* Get rid of old string. */
4112 if (IS_STRING_ITEM(menu->fType) && menu->text) {
4113 HeapFree(GetProcessHeap(), 0, menu->text);
4117 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4118 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4119 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4121 menu->text = lpmii->dwTypeData;
4123 if (IS_STRING_ITEM(menu->fType))
4124 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4127 if (lpmii->fMask & MIIM_FTYPE ) {
4128 /* free the string when the type is changing */
4129 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4130 HeapFree(GetProcessHeap(), 0, menu->text);
4133 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4134 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4135 if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4136 menu->fType |= MF_SEPARATOR;
4139 if (lpmii->fMask & MIIM_STRING ) {
4140 if (IS_STRING_ITEM(menu->fType)) {
4141 /* free the string when used */
4142 HeapFree(GetProcessHeap(), 0, menu->text);
4143 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4147 if (lpmii->fMask & MIIM_STATE)
4149 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4150 menu->fState = lpmii->fState;
4153 if (lpmii->fMask & MIIM_ID)
4154 menu->wID = lpmii->wID;
4156 if (lpmii->fMask & MIIM_SUBMENU) {
4157 menu->hSubMenu = lpmii->hSubMenu;
4158 if (menu->hSubMenu) {
4159 POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
4161 subMenu->wFlags |= MF_POPUP;
4162 menu->fType |= MF_POPUP;
4165 /* FIXME: Return an error ? */
4166 menu->fType &= ~MF_POPUP;
4169 menu->fType &= ~MF_POPUP;
4172 if (lpmii->fMask & MIIM_CHECKMARKS)
4174 if (lpmii->fType & MFT_RADIOCHECK)
4175 menu->fType |= MFT_RADIOCHECK;
4177 menu->hCheckBit = lpmii->hbmpChecked;
4178 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4180 if (lpmii->fMask & MIIM_DATA)
4181 menu->dwItemData = lpmii->dwItemData;
4183 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4187 /**********************************************************************
4188 * SetMenuItemInfoA (USER32.@)
4190 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4191 const MENUITEMINFOA *lpmii)
4193 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4194 (const MENUITEMINFOW *)lpmii, FALSE);
4197 /**********************************************************************
4198 * SetMenuItemInfoW (USER32.@)
4200 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4201 const MENUITEMINFOW *lpmii)
4203 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4207 /**********************************************************************
4208 * SetMenuDefaultItem (USER32.@)
4211 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4217 TRACE("(%p,%d,%d)\n", hmenu, uItem, bypos);
4219 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4221 /* reset all default-item flags */
4223 for (i = 0; i < menu->nItems; i++, item++)
4225 item->fState &= ~MFS_DEFAULT;
4228 /* no default item */
4237 if ( uItem >= menu->nItems ) return FALSE;
4238 item[uItem].fState |= MFS_DEFAULT;
4243 for (i = 0; i < menu->nItems; i++, item++)
4245 if (item->wID == uItem)
4247 item->fState |= MFS_DEFAULT;
4256 /**********************************************************************
4257 * GetMenuDefaultItem (USER32.@)
4259 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4265 TRACE("(%p,%d,%d)\n", hmenu, bypos, flags);
4267 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4269 /* find default item */
4273 if (! item) return -1;
4275 while ( !( item->fState & MFS_DEFAULT ) )
4278 if (i >= menu->nItems ) return -1;
4281 /* default: don't return disabled items */
4282 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4284 /* search rekursiv when needed */
4285 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4288 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4289 if ( -1 != ret ) return ret;
4291 /* when item not found in submenu, return the popup item */
4293 return ( bypos ) ? i : item->wID;
4298 /**********************************************************************
4299 * InsertMenuItemA (USER32.@)
4301 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4302 const MENUITEMINFOA *lpmii)
4304 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4305 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4309 /**********************************************************************
4310 * InsertMenuItemW (USER32.@)
4312 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4313 const MENUITEMINFOW *lpmii)
4315 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4316 return SetMenuItemInfo_common(item, lpmii, TRUE);
4319 /**********************************************************************
4320 * CheckMenuRadioItem (USER32.@)
4323 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4324 UINT first, UINT last, UINT check,
4327 MENUITEM *mifirst, *milast, *micheck;
4328 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4330 TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos);
4332 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4333 milast = MENU_FindItem (&mlast, &last, bypos);
4334 micheck = MENU_FindItem (&mcheck, &check, bypos);
4336 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4337 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4338 micheck > milast || micheck < mifirst)
4341 while (mifirst <= milast)
4343 if (mifirst == micheck)
4345 mifirst->fType |= MFT_RADIOCHECK;
4346 mifirst->fState |= MFS_CHECKED;
4348 mifirst->fType &= ~MFT_RADIOCHECK;
4349 mifirst->fState &= ~MFS_CHECKED;
4358 /**********************************************************************
4359 * GetMenuItemRect (USER32.@)
4361 * ATTENTION: Here, the returned values in rect are the screen
4362 * coordinates of the item just like if the menu was
4363 * always on the upper left side of the application.
4366 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4369 POPUPMENU *itemMenu;
4373 TRACE("(%p,%p,%d,%p)\n", hwnd, hMenu, uItem, rect);
4375 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4376 referenceHwnd = hwnd;
4380 itemMenu = MENU_GetMenu(hMenu);
4381 if (itemMenu == NULL)
4384 if(itemMenu->hWnd == 0)
4386 referenceHwnd = itemMenu->hWnd;
4389 if ((rect == NULL) || (item == NULL))
4394 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4400 /**********************************************************************
4401 * SetMenuInfo (USER32.@)
4404 * MIM_APPLYTOSUBMENUS
4405 * actually use the items to draw the menu
4407 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4411 TRACE("(%p %p)\n", hMenu, lpmi);
4413 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4416 if (lpmi->fMask & MIM_BACKGROUND)
4417 menu->hbrBack = lpmi->hbrBack;
4419 if (lpmi->fMask & MIM_HELPID)
4420 menu->dwContextHelpID = lpmi->dwContextHelpID;
4422 if (lpmi->fMask & MIM_MAXHEIGHT)
4423 menu->cyMax = lpmi->cyMax;
4425 if (lpmi->fMask & MIM_MENUDATA)
4426 menu->dwMenuData = lpmi->dwMenuData;
4428 if (lpmi->fMask & MIM_STYLE)
4429 menu->dwStyle = lpmi->dwStyle;
4436 /**********************************************************************
4437 * GetMenuInfo (USER32.@)
4443 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4446 TRACE("(%p %p)\n", hMenu, lpmi);
4448 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4451 if (lpmi->fMask & MIM_BACKGROUND)
4452 lpmi->hbrBack = menu->hbrBack;
4454 if (lpmi->fMask & MIM_HELPID)
4455 lpmi->dwContextHelpID = menu->dwContextHelpID;
4457 if (lpmi->fMask & MIM_MAXHEIGHT)
4458 lpmi->cyMax = menu->cyMax;
4460 if (lpmi->fMask & MIM_MENUDATA)
4461 lpmi->dwMenuData = menu->dwMenuData;
4463 if (lpmi->fMask & MIM_STYLE)
4464 lpmi->dwStyle = menu->dwStyle;
4472 /**********************************************************************
4473 * SetMenuContextHelpId (USER32.@)
4475 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4479 TRACE("(%p 0x%08lx)\n", hMenu, dwContextHelpID);
4481 if ((menu = MENU_GetMenu(hMenu)))
4483 menu->dwContextHelpID = dwContextHelpID;
4490 /**********************************************************************
4491 * GetMenuContextHelpId (USER32.@)
4493 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4497 TRACE("(%p)\n", hMenu);
4499 if ((menu = MENU_GetMenu(hMenu)))
4501 return menu->dwContextHelpID;
4506 /**********************************************************************
4507 * MenuItemFromPoint (USER32.@)
4509 INT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4511 POPUPMENU *menu = MENU_GetMenu(hMenu);
4514 /*FIXME: Do we have to handle hWnd here? */
4515 if (!menu) return -1;
4516 if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
4521 /**********************************************************************
4522 * translate_accelerator
4524 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4525 BYTE fVirt, WORD key, WORD cmd )
4530 if (wParam != key) return FALSE;
4532 if (GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4533 if (GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4534 if (GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4536 if (message == WM_CHAR || message == WM_SYSCHAR)
4538 if ( !(fVirt & FVIRTKEY) && (mask & FALT) == (fVirt & FALT) )
4540 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4546 if(fVirt & FVIRTKEY)
4548 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4549 wParam, 0xff & HIWORD(lParam));
4551 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4552 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4556 if (!(lParam & 0x01000000)) /* no special_key */
4558 if ((fVirt & FALT) && (lParam & 0x20000000))
4559 { /* ^^ ALT pressed */
4560 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4569 if (message == WM_KEYUP || message == WM_SYSKEYUP)
4573 HMENU hMenu, hSubMenu, hSysMenu;
4574 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4576 hMenu = (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4577 hSysMenu = get_win_sys_menu( hWnd );
4579 /* find menu item and ask application to initialize it */
4580 /* 1. in the system menu */
4581 hSubMenu = hSysMenu;
4583 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4587 if (!IsWindowEnabled(hWnd))
4591 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4592 if(hSubMenu != hSysMenu)
4594 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4595 TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4596 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4598 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4601 else /* 2. in the window's menu */
4605 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4609 if (!IsWindowEnabled(hWnd))
4613 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4614 if(hSubMenu != hMenu)
4616 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4617 TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
4618 SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4620 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4627 if (uSysStat != (UINT)-1)
4629 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4636 if (uStat != (UINT)-1)
4642 if (uStat & (MF_DISABLED|MF_GRAYED))
4654 if( mesg==WM_COMMAND )
4656 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4657 SendMessageW(hWnd, mesg, 0x10000 | cmd, 0L);
4659 else if( mesg==WM_SYSCOMMAND )
4661 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4662 SendMessageW(hWnd, mesg, cmd, 0x00010000L);
4666 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4667 * #0: unknown (please report!)
4668 * #1: for WM_KEYUP,WM_SYSKEYUP
4669 * #2: mouse is captured
4670 * #3: window is disabled
4671 * #4: it's a disabled system menu option
4672 * #5: it's a menu option, but window is iconic
4673 * #6: it's a menu option, but disabled
4675 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4677 ERR_(accel)(" unknown reason - please report!\n");
4682 /**********************************************************************
4683 * TranslateAccelerator (USER32.@)
4684 * TranslateAcceleratorA (USER32.@)
4686 INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg )
4689 LPACCEL16 lpAccelTbl;
4693 if (!hWnd || !msg) return 0;
4695 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
4697 WARN_(accel)("invalid accel handle=%p\n", hAccel);
4701 wParam = msg->wParam;
4703 switch (msg->message)
4712 char ch = LOWORD(wParam);
4714 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
4715 wParam = MAKEWPARAM(wch, HIWORD(wParam));
4723 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4724 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4728 if (translate_accelerator( hWnd, msg->message, wParam, msg->lParam,
4729 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4731 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
4736 /**********************************************************************
4737 * TranslateAcceleratorW (USER32.@)
4739 INT WINAPI TranslateAcceleratorW( HWND hWnd, HACCEL hAccel, LPMSG msg )
4742 LPACCEL16 lpAccelTbl;
4745 if (!hWnd || !msg) return 0;
4747 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
4749 WARN_(accel)("invalid accel handle=%p\n", hAccel);
4753 switch (msg->message)
4765 TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4766 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4770 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
4771 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4773 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);