4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
10 * Note: the style MF_MOUSESELECT is used to mark popup items that
11 * have been selected, i.e. their popup menu is currently displayed.
12 * This is probably not the meaning this style has in MS-Windows.
23 #include "wine/winbase16.h"
24 #include "wine/winuser16.h"
25 #include "wine/unicode.h"
26 #include "wine/port.h"
31 #include "nonclient.h"
37 #include "debugtools.h"
39 DEFAULT_DEBUG_CHANNEL(menu);
40 DECLARE_DEBUG_CHANNEL(accel);
42 /* internal popup menu window messages */
44 #define MM_SETMENUHANDLE (WM_USER + 0)
45 #define MM_GETMENUHANDLE (WM_USER + 1)
47 /* Menu item structure */
49 /* ----------- MENUITEMINFO Stuff ----------- */
50 UINT fType; /* Item type. */
51 UINT fState; /* Item state. */
52 UINT wID; /* Item id. */
53 HMENU hSubMenu; /* Pop-up menu. */
54 HBITMAP hCheckBit; /* Bitmap when checked. */
55 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
56 LPWSTR text; /* Item text or bitmap handle. */
57 DWORD dwItemData; /* Application defined. */
58 DWORD dwTypeData; /* depends on fMask */
59 HBITMAP hbmpItem; /* bitmap in win98 style menus */
60 /* ----------- Wine stuff ----------- */
61 RECT rect; /* Item area (relative to menu window) */
62 UINT xTab; /* X position of text after Tab */
65 /* Popup menu structure */
67 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
68 WORD wMagic; /* Magic number */
69 HQUEUE16 hTaskQ; /* Task queue for this menu */
70 WORD Width; /* Width of the whole menu */
71 WORD Height; /* Height of the whole menu */
72 WORD nItems; /* Number of items in the menu */
73 HWND hWnd; /* Window containing the menu */
74 MENUITEM *items; /* Array of menu items */
75 UINT FocusedItem; /* Currently focused item */
76 HWND hwndOwner; /* window receiving the messages for ownerdraw */
77 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
78 /* ------------ MENUINFO members ------ */
79 DWORD dwStyle; /* Extended mennu style */
80 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
81 HBRUSH hbrBack; /* brush for menu background */
82 DWORD dwContextHelpID;
83 DWORD dwMenuData; /* application defined value */
84 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
85 } POPUPMENU, *LPPOPUPMENU;
87 /* internal flags for menu tracking */
89 #define TF_ENDMENU 0x0001
90 #define TF_SUSPENDPOPUP 0x0002
91 #define TF_SKIPREMOVE 0x0004
96 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
97 HMENU hTopMenu; /* initial menu */
98 HWND hOwnerWnd; /* where notifications are sent */
102 #define MENU_MAGIC 0x554d /* 'MU' */
103 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
108 /* Internal MENU_TrackMenu() flags */
109 #define TPM_INTERNAL 0xF0000000
110 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
111 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
112 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
114 /* popup menu shade thickness */
115 #define POPUP_XSHADE 4
116 #define POPUP_YSHADE 4
118 /* Space between 2 menu bar items */
119 #define MENU_BAR_ITEMS_SPACE 12
121 /* Minimum width of a tab character */
122 #define MENU_TAB_SPACE 8
124 /* Height of a separator item */
125 #define SEPARATOR_HEIGHT 5
127 /* (other menu->FocusedItem values give the position of the focused item) */
128 #define NO_SELECTED_ITEM 0xffff
130 #define MENU_ITEM_TYPE(flags) \
131 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
133 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
134 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
135 #define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
137 #define IS_SYSTEM_MENU(menu) \
138 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
140 #define IS_SYSTEM_POPUP(menu) \
141 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
143 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
144 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
145 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
146 MF_POPUP | MF_SYSMENU | MF_HELP)
147 #define STATE_MASK (~TYPE_MASK)
149 /* Dimension of the menu bitmaps */
150 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
151 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
153 static HBITMAP hStdRadioCheck = 0;
154 static HBITMAP hStdCheck = 0;
155 static HBITMAP hStdMnArrow = 0;
157 /* Minimze/restore/close buttons to be inserted in menubar */
158 static HBITMAP hBmpMinimize = 0;
159 static HBITMAP hBmpMinimizeD = 0;
160 static HBITMAP hBmpMaximize = 0;
161 static HBITMAP hBmpMaximizeD = 0;
162 static HBITMAP hBmpClose = 0;
163 static HBITMAP hBmpCloseD = 0;
166 static HBRUSH hShadeBrush = 0;
167 static HFONT hMenuFont = 0;
168 static HFONT hMenuFontBold = 0;
170 static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
172 /* Use global popup window because there's no way 2 menus can
173 * be tracked at the same time. */
175 static WND* pTopPopupWnd = 0;
176 static UINT uSubPWndLevel = 0;
178 /* Flag set by EndMenu() to force an exit from menu tracking */
179 static BOOL fEndMenu = FALSE;
181 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
184 /*********************************************************************
185 * menu class descriptor
187 const struct builtin_class_descr MENU_builtin_class =
189 POPUPMENU_CLASS_ATOM, /* name */
190 CS_GLOBALCLASS | CS_SAVEBITS, /* style */
191 NULL, /* procA (winproc is Unicode only) */
192 PopupMenuWndProc, /* procW */
193 sizeof(HMENU), /* extra */
194 IDC_ARROWA, /* cursor */
195 COLOR_MENU+1 /* brush */
199 /***********************************************************************
200 * debug_print_menuitem
202 * Print a menuitem in readable form.
205 #define debug_print_menuitem(pre, mp, post) \
206 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
208 #define MENUOUT(text) \
209 DPRINTF("%s%s", (count++ ? "," : ""), (text))
211 #define MENUFLAG(bit,text) \
213 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
216 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
219 TRACE("%s ", prefix);
221 UINT flags = mp->fType;
222 int typ = MENU_ITEM_TYPE(flags);
223 DPRINTF( "{ ID=0x%x", mp->wID);
224 if (flags & MF_POPUP)
225 DPRINTF( ", Sub=0x%x", mp->hSubMenu);
229 if (typ == MFT_STRING)
231 else if (typ == MFT_SEPARATOR)
233 else if (typ == MFT_OWNERDRAW)
235 else if (typ == MFT_BITMAP)
241 MENUFLAG(MF_POPUP, "pop");
242 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
243 MENUFLAG(MFT_MENUBREAK, "brk");
244 MENUFLAG(MFT_RADIOCHECK, "radio");
245 MENUFLAG(MFT_RIGHTORDER, "rorder");
246 MENUFLAG(MF_SYSMENU, "sys");
247 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
250 DPRINTF( "+0x%x", flags);
255 DPRINTF( ", State=");
256 MENUFLAG(MFS_GRAYED, "grey");
257 MENUFLAG(MFS_DEFAULT, "default");
258 MENUFLAG(MFS_DISABLED, "dis");
259 MENUFLAG(MFS_CHECKED, "check");
260 MENUFLAG(MFS_HILITE, "hi");
261 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
262 MENUFLAG(MF_MOUSESELECT, "mouse");
264 DPRINTF( "+0x%x", flags);
267 DPRINTF( ", Chk=0x%x", mp->hCheckBit);
269 DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
271 if (typ == MFT_STRING) {
273 DPRINTF( ", Text=\"%s\"", debugstr_w(mp->text));
275 DPRINTF( ", Text=Null");
276 } else if (mp->text == NULL)
279 DPRINTF( ", Text=%p", mp->text);
281 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
287 DPRINTF(" %s\n", postfix);
294 /***********************************************************************
297 * Validate the given menu handle and returns the menu structure pointer.
299 POPUPMENU *MENU_GetMenu(HMENU hMenu)
302 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
303 if (!IS_A_MENU(menu))
305 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
311 /***********************************************************************
314 * Return the default system menu.
316 static HMENU MENU_CopySysPopup(void)
318 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
321 POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
322 menu->wFlags |= MF_SYSMENU | MF_POPUP;
323 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
327 ERR("Unable to load default system menu\n" );
330 TRACE("returning %x.\n", hMenu );
335 /***********************************************************************
336 * MENU_GetTopPopupWnd()
338 * Return the locked pointer pTopPopupWnd.
340 static WND *MENU_GetTopPopupWnd()
342 return WIN_LockWndPtr(pTopPopupWnd);
344 /***********************************************************************
345 * MENU_ReleaseTopPopupWnd()
347 * Release the locked pointer pTopPopupWnd.
349 static void MENU_ReleaseTopPopupWnd()
351 WIN_ReleaseWndPtr(pTopPopupWnd);
353 /***********************************************************************
354 * MENU_DestroyTopPopupWnd()
356 * Destroy the locked pointer pTopPopupWnd.
358 static void MENU_DestroyTopPopupWnd()
360 WND *tmpWnd = pTopPopupWnd;
362 WIN_ReleaseWndPtr(tmpWnd);
367 /**********************************************************************
370 * Create a copy of the system menu. System menu in Windows is
371 * a special menu bar with the single entry - system menu popup.
372 * This popup is presented to the outside world as a "system menu".
373 * However, the real system menu handle is sometimes seen in the
374 * WM_MENUSELECT parameters (and Word 6 likes it this way).
376 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
380 if ((hMenu = CreateMenu()))
382 POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
383 menu->wFlags = MF_SYSMENU;
386 if (hPopupMenu == (HMENU)(-1))
387 hPopupMenu = MENU_CopySysPopup();
388 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
392 InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
394 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
395 menu->items[0].fState = 0;
396 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
397 menu->wFlags |= MF_SYSMENU;
399 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
402 DestroyMenu( hMenu );
404 ERR("failed to load system menu!\n");
409 /***********************************************************************
412 * Menus initialisation.
417 NONCLIENTMETRICSA ncm;
419 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
424 /* Load menu bitmaps */
425 hStdCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK));
426 hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK));
427 hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
428 /* Load system buttons bitmaps */
429 hBmpMinimize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE));
430 hBmpMinimizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED));
431 hBmpMaximize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE));
432 hBmpMaximizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED));
433 hBmpClose = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE));
434 hBmpCloseD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED));
439 GetObjectA( hStdCheck, sizeof(bm), &bm );
440 check_bitmap_width = bm.bmWidth;
441 check_bitmap_height = bm.bmHeight;
445 /* Assume that radio checks have the same size as regular checks. */
452 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
453 arrow_bitmap_width = bm.bmWidth;
454 arrow_bitmap_height = bm.bmHeight;
458 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
461 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
464 DeleteObject( hBitmap );
465 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
468 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
469 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
472 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
475 ncm.lfMenuFont.lfWeight += 300;
476 if ( ncm.lfMenuFont.lfWeight > 1000)
477 ncm.lfMenuFont.lfWeight = 1000;
479 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
485 /***********************************************************************
486 * MENU_InitSysMenuPopup
488 * Grey the appropriate items in System menu.
490 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
494 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
495 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
496 gray = ((style & WS_MAXIMIZE) != 0);
497 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
498 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
499 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
500 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
501 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
502 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
503 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
504 gray = (clsStyle & CS_NOCLOSE) != 0;
506 /* The menu item must keep its state if it's disabled */
508 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
512 /******************************************************************************
514 * UINT MENU_GetStartOfNextColumn(
517 *****************************************************************************/
519 static UINT MENU_GetStartOfNextColumn(
522 POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
523 UINT i = menu->FocusedItem + 1;
526 return NO_SELECTED_ITEM;
528 if( i == NO_SELECTED_ITEM )
531 for( ; i < menu->nItems; ++i ) {
532 if (menu->items[i].fType & MF_MENUBARBREAK)
536 return NO_SELECTED_ITEM;
540 /******************************************************************************
542 * UINT MENU_GetStartOfPrevColumn(
545 *****************************************************************************/
547 static UINT MENU_GetStartOfPrevColumn(
550 POPUPMENU const *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
554 return NO_SELECTED_ITEM;
556 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
557 return NO_SELECTED_ITEM;
559 /* Find the start of the column */
561 for(i = menu->FocusedItem; i != 0 &&
562 !(menu->items[i].fType & MF_MENUBARBREAK);
566 return NO_SELECTED_ITEM;
568 for(--i; i != 0; --i) {
569 if (menu->items[i].fType & MF_MENUBARBREAK)
573 TRACE("ret %d.\n", i );
580 /***********************************************************************
583 * Find a menu item. Return a pointer on the item, and modifies *hmenu
584 * in case the item was in a sub-menu.
586 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
591 if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
592 if (wFlags & MF_BYPOSITION)
594 if (*nPos >= menu->nItems) return NULL;
595 return &menu->items[*nPos];
599 MENUITEM *item = menu->items;
600 for (i = 0; i < menu->nItems; i++, item++)
602 if (item->wID == *nPos)
607 else if (item->fType & MF_POPUP)
609 HMENU hsubmenu = item->hSubMenu;
610 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
622 /***********************************************************************
625 * Find a Sub menu. Return the position of the submenu, and modifies
626 * *hmenu in case it is found in another sub-menu.
627 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
629 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
634 if (((*hmenu)==0xffff) ||
635 (!(menu = MENU_GetMenu(*hmenu))))
636 return NO_SELECTED_ITEM;
638 for (i = 0; i < menu->nItems; i++, item++) {
639 if(!(item->fType & MF_POPUP)) continue;
640 if (item->hSubMenu == hSubTarget) {
644 HMENU hsubmenu = item->hSubMenu;
645 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
646 if (pos != NO_SELECTED_ITEM) {
652 return NO_SELECTED_ITEM;
655 /***********************************************************************
658 static void MENU_FreeItemData( MENUITEM* item )
661 if (IS_STRING_ITEM(item->fType) && item->text)
662 HeapFree( SystemHeap, 0, item->text );
665 /***********************************************************************
666 * MENU_FindItemByCoords
668 * Find the item at the specified coordinates (screen coords). Does
669 * not work for child windows and therefore should not be called for
670 * an arbitrary system menu.
672 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
673 POINT pt, UINT *pos )
679 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
680 pt.x -= wrect.left;pt.y -= wrect.top;
682 for (i = 0; i < menu->nItems; i++, item++)
684 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
685 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
695 /***********************************************************************
698 * Find the menu item selected by a key press.
699 * Return item id, -1 if none, -2 if we should close the menu.
701 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
702 UINT key, BOOL forceMenuChar )
704 TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
706 if (!IsMenu( hmenu ))
708 WND* w = WIN_FindWndPtr(hwndOwner);
709 hmenu = GetSubMenu(w->hSysMenu, 0);
710 WIN_ReleaseWndPtr(w);
715 POPUPMENU *menu = MENU_GetMenu( hmenu );
716 MENUITEM *item = menu->items;
724 for (i = 0; i < menu->nItems; i++, item++)
726 if (item->text && (IS_STRING_ITEM(item->fType)))
728 WCHAR *p = item->text - 2;
731 p = strchrW (p + 2, '&');
733 while (p != NULL && p [1] == '&');
734 if (p && (toupper(p[1]) == key)) return i;
738 menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
739 MAKEWPARAM( key, menu->wFlags ), hmenu );
740 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
741 if (HIWORD(menuchar) == 1) return (UINT)(-2);
745 /***********************************************************************
748 * Load the bitmap associated with the magic menu item and its style
751 static HBITMAP MENU_LoadMagicItem(UINT id, BOOL hilite, DWORD dwItemData)
754 * Magic menu item id's section
755 * These magic id's are used by windows to insert "standard" mdi
756 * buttons (minimize,restore,close) on menu. Under windows,
757 * these magic id's make sure the right things appear when those
758 * bitmap buttons are pressed/selected/released.
762 { case HBMMENU_SYSTEM:
763 return (dwItemData) ?
764 (HBITMAP)dwItemData :
765 (hilite ? hBmpMinimizeD : hBmpMinimize);
766 case HBMMENU_MBAR_RESTORE:
767 return (hilite ? hBmpMaximizeD: hBmpMaximize);
768 case HBMMENU_MBAR_MINIMIZE:
769 return (hilite ? hBmpMinimizeD : hBmpMinimize);
770 case HBMMENU_MBAR_CLOSE:
771 return (hilite ? hBmpCloseD : hBmpClose);
772 case HBMMENU_CALLBACK:
773 case HBMMENU_MBAR_CLOSE_D:
774 case HBMMENU_MBAR_MINIMIZE_D:
775 case HBMMENU_POPUP_CLOSE:
776 case HBMMENU_POPUP_RESTORE:
777 case HBMMENU_POPUP_MAXIMIZE:
778 case HBMMENU_POPUP_MINIMIZE:
780 FIXME("Magic 0x%08x not implemented\n", id);
786 /***********************************************************************
789 * Calculate the size of the menu item and store it in lpitem->rect.
791 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
792 INT orgX, INT orgY, BOOL menuBar )
796 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
797 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
798 (menuBar ? " (MenuBar)" : ""));
800 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
802 if (lpitem->fType & MF_OWNERDRAW)
805 ** Experimentation under Windows reveals that an owner-drawn
806 ** menu is expected to return the size of the content part of
807 ** the menu item, not including the checkmark nor the submenu
808 ** arrow. Windows adds those values itself and returns the
809 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
811 MEASUREITEMSTRUCT mis;
812 mis.CtlType = ODT_MENU;
814 mis.itemID = lpitem->wID;
815 mis.itemData = (DWORD)lpitem->dwItemData;
818 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
819 lpitem->rect.right += mis.itemWidth;
823 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
826 /* under at least win95 you seem to be given a standard
827 height for the menu and the height value is ignored */
829 if (TWEAK_WineLook == WIN31_LOOK)
830 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
832 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
835 lpitem->rect.bottom += mis.itemHeight;
837 TRACE("id=%04x size=%dx%d\n",
838 lpitem->wID, mis.itemWidth, mis.itemHeight);
839 /* Fall through to get check/arrow width calculation. */
842 if (lpitem->fType & MF_SEPARATOR)
844 lpitem->rect.bottom += SEPARATOR_HEIGHT;
850 lpitem->rect.right += 2 * check_bitmap_width;
851 if (lpitem->fType & MF_POPUP)
852 lpitem->rect.right += arrow_bitmap_width;
855 if (lpitem->fType & MF_OWNERDRAW)
858 if (IS_BITMAP_ITEM(lpitem->fType))
863 /* Check if there is a magic menu item associated with this item */
864 if (IS_MAGIC_ITEM(lpitem->text))
866 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fType & MF_HILITE),
870 resBmp = (HBITMAP)lpitem->text;
872 if (GetObjectA(resBmp, sizeof(bm), &bm ))
874 lpitem->rect.right += bm.bmWidth;
875 lpitem->rect.bottom += bm.bmHeight;
876 if (TWEAK_WineLook == WIN98_LOOK) {
877 /* Leave space for the sunken border */
878 lpitem->rect.right += 2;
879 lpitem->rect.bottom += 2;
886 /* If we get here, then it must be a text item */
887 if (IS_STRING_ITEM( lpitem->fType ))
890 GetTextExtentPoint32W(hdc, lpitem->text, strlenW(lpitem->text), &size);
892 lpitem->rect.right += size.cx;
893 if (TWEAK_WineLook == WIN31_LOOK)
894 lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
896 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
901 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
903 else if ((p = strchrW( lpitem->text, '\t' )) != NULL)
905 /* Item contains a tab (only meaningful in popup menus) */
906 GetTextExtentPoint32W(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
907 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
908 lpitem->rect.right += MENU_TAB_SPACE;
912 if (strchrW( lpitem->text, '\b' ))
913 lpitem->rect.right += MENU_TAB_SPACE;
914 lpitem->xTab = lpitem->rect.right - check_bitmap_width
915 - arrow_bitmap_width;
918 TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
922 /***********************************************************************
923 * MENU_PopupMenuCalcSize
925 * Calculate the size of a popup menu.
927 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
932 int orgX, orgY, maxX, maxTab, maxTabWidth;
934 lppop->Width = lppop->Height = 0;
935 if (lppop->nItems == 0) return;
938 SelectObject( hdc, hMenuFont);
941 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2+1 ;
943 while (start < lppop->nItems)
945 lpitem = &lppop->items[start];
947 orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
949 maxTab = maxTabWidth = 0;
951 /* Parse items until column break or end of menu */
952 for (i = start; i < lppop->nItems; i++, lpitem++)
955 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
957 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
959 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
960 maxX = max( maxX, lpitem->rect.right );
961 orgY = lpitem->rect.bottom;
962 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
964 maxTab = max( maxTab, lpitem->xTab );
965 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
969 /* Finish the column (set all items to the largest width found) */
970 maxX = max( maxX, maxTab + maxTabWidth );
971 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
973 lpitem->rect.right = maxX;
974 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
975 lpitem->xTab = maxTab;
978 lppop->Height = max( lppop->Height, orgY );
983 /* space for 3d border */
984 if(TWEAK_WineLook > WIN31_LOOK)
994 /***********************************************************************
995 * MENU_MenuBarCalcSize
997 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
998 * height is off by 1 pixel which causes lengthy window relocations when
999 * active document window is maximized/restored.
1001 * Calculate the size of the menu bar.
1003 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1004 LPPOPUPMENU lppop, HWND hwndOwner )
1007 int start, i, orgX, orgY, maxY, helpPos;
1009 if ((lprect == NULL) || (lppop == NULL)) return;
1010 if (lppop->nItems == 0) return;
1011 TRACE("left=%d top=%d right=%d bottom=%d\n",
1012 lprect->left, lprect->top, lprect->right, lprect->bottom);
1013 lppop->Width = lprect->right - lprect->left;
1015 maxY = lprect->top+1;
1018 while (start < lppop->nItems)
1020 lpitem = &lppop->items[start];
1021 orgX = lprect->left;
1024 /* Parse items until line break or end of menu */
1025 for (i = start; i < lppop->nItems; i++, lpitem++)
1027 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
1029 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1031 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1033 debug_print_menuitem (" item: ", lpitem, "");
1034 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1036 if (lpitem->rect.right > lprect->right)
1038 if (i != start) break;
1039 else lpitem->rect.right = lprect->right;
1041 maxY = max( maxY, lpitem->rect.bottom );
1042 orgX = lpitem->rect.right;
1045 /* Finish the line (set all items to the largest height found) */
1046 while (start < i) lppop->items[start++].rect.bottom = maxY;
1049 lprect->bottom = maxY;
1050 lppop->Height = lprect->bottom - lprect->top;
1052 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1053 /* the last item (if several lines, only move the last line) */
1054 lpitem = &lppop->items[lppop->nItems-1];
1055 orgY = lpitem->rect.top;
1056 orgX = lprect->right;
1057 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1058 if ( (helpPos==-1) || (helpPos>i) )
1060 if (lpitem->rect.top != orgY) break; /* Other line */
1061 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1062 lpitem->rect.left += orgX - lpitem->rect.right;
1063 lpitem->rect.right = orgX;
1064 orgX = lpitem->rect.left;
1068 /***********************************************************************
1071 * Draw a single menu item.
1073 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1074 UINT height, BOOL menuBar, UINT odaction )
1078 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1080 if (lpitem->fType & MF_SYSMENU)
1082 if( !IsIconic(hwnd) ) {
1083 if (TWEAK_WineLook > WIN31_LOOK)
1084 NC_DrawSysButton95( hwnd, hdc,
1086 (MF_HILITE | MF_MOUSESELECT) );
1088 NC_DrawSysButton( hwnd, hdc,
1090 (MF_HILITE | MF_MOUSESELECT) );
1096 if (lpitem->fType & MF_OWNERDRAW)
1099 ** Experimentation under Windows reveals that an owner-drawn
1100 ** menu is given the rectangle which includes the space it requested
1101 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1102 ** and a popup-menu arrow. This is the value of lpitem->rect.
1103 ** Windows will leave all drawing to the application except for
1104 ** the popup-menu arrow. Windows always draws that itself, after
1105 ** the menu owner has finished drawing.
1109 dis.CtlType = ODT_MENU;
1111 dis.itemID = lpitem->wID;
1112 dis.itemData = (DWORD)lpitem->dwItemData;
1114 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1115 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED;
1116 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1117 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1118 dis.hwndItem = hmenu;
1120 dis.rcItem = lpitem->rect;
1121 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1122 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
1123 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1124 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1126 SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1127 /* Fall through to draw popup-menu arrow */
1130 TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
1131 lpitem->rect.right,lpitem->rect.bottom);
1133 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1135 rect = lpitem->rect;
1137 if (!(lpitem->fType & MF_OWNERDRAW))
1139 if (lpitem->fState & MF_HILITE)
1141 if(TWEAK_WineLook == WIN98_LOOK)
1144 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1146 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1148 else /* Not Win98 Look */
1150 if(!IS_BITMAP_ITEM(lpitem->fType))
1151 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1155 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1158 SetBkMode( hdc, TRANSPARENT );
1160 if (!(lpitem->fType & MF_OWNERDRAW))
1162 /* vertical separator */
1163 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1165 if (TWEAK_WineLook > WIN31_LOOK)
1169 rc.bottom = height - 3;
1170 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1174 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1175 MoveToEx( hdc, rect.left, 0, NULL );
1176 LineTo( hdc, rect.left, height );
1180 /* horizontal separator */
1181 if (lpitem->fType & MF_SEPARATOR)
1183 if (TWEAK_WineLook > WIN31_LOOK)
1188 rc.top += SEPARATOR_HEIGHT / 2;
1189 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1193 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1194 MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
1195 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1203 if (lpitem->fState & MF_HILITE)
1205 if(TWEAK_WineLook == WIN98_LOOK)
1208 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1209 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1211 if(lpitem->fState & MF_GRAYED)
1212 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1214 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1215 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1218 else /* Not Win98 Look */
1220 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1221 if(!IS_BITMAP_ITEM(lpitem->fType))
1222 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1227 if (lpitem->fState & MF_GRAYED)
1228 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1230 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1231 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1234 /* helper lines for debugging */
1235 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1236 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1237 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1238 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1243 INT y = rect.top + rect.bottom;
1245 if (!(lpitem->fType & MF_OWNERDRAW))
1247 /* Draw the check mark
1250 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1253 if (lpitem->fState & MF_CHECKED)
1255 HBITMAP bm = lpitem->hCheckBit ? lpitem->hCheckBit :
1256 ((lpitem->fType & MFT_RADIOCHECK) ? hStdRadioCheck : hStdCheck);
1257 HDC hdcMem = CreateCompatibleDC( hdc );
1259 SelectObject( hdcMem, bm );
1260 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1261 check_bitmap_width, check_bitmap_height,
1262 hdcMem, 0, 0, SRCCOPY );
1265 else if (lpitem->hUnCheckBit)
1267 HDC hdcMem = CreateCompatibleDC( hdc );
1269 SelectObject( hdcMem, lpitem->hUnCheckBit );
1270 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1271 check_bitmap_width, check_bitmap_height,
1272 hdcMem, 0, 0, SRCCOPY );
1277 /* Draw the popup-menu arrow */
1278 if (lpitem->fType & MF_POPUP)
1280 HDC hdcMem = CreateCompatibleDC( hdc );
1281 HBITMAP hOrigBitmap;
1283 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1284 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1285 (y - arrow_bitmap_height) / 2,
1286 arrow_bitmap_width, arrow_bitmap_height,
1287 hdcMem, 0, 0, SRCCOPY );
1288 SelectObject( hdcMem, hOrigBitmap );
1292 rect.left += check_bitmap_width;
1293 rect.right -= arrow_bitmap_width;
1296 /* Done for owner-drawn */
1297 if (lpitem->fType & MF_OWNERDRAW)
1300 /* Draw the item text or bitmap */
1301 if (IS_BITMAP_ITEM(lpitem->fType))
1308 HDC hdcMem = CreateCompatibleDC( hdc );
1311 * Check if there is a magic menu item associated with this item
1312 * and load the appropriate bitmap
1314 if (IS_MAGIC_ITEM(lpitem->text))
1316 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fState & MF_HILITE),
1317 lpitem->dwItemData);
1320 resBmp = (HBITMAP)lpitem->text;
1325 GetObjectA( resBmp, sizeof(bm), &bm );
1327 SelectObject(hdcMem,resBmp );
1329 /* handle fontsize > bitmap_height */
1330 h=rect.bottom - rect.top;
1331 top = (h>bm.bmHeight) ?
1332 rect.top+(h-bm.bmHeight)/2 : rect.top;
1333 w=rect.right - rect.left;
1335 if (TWEAK_WineLook == WIN95_LOOK) {
1336 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text)) ? NOTSRCCOPY : SRCCOPY;
1337 if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
1338 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1342 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text) && (!menuBar)) ? MERGEPAINT : SRCCOPY;
1344 BitBlt( hdc, left, top, w,
1353 /* No bitmap - process text if present */
1354 else if (IS_STRING_ITEM(lpitem->fType))
1359 UINT uFormat = (menuBar) ?
1360 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1361 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1363 if ( lpitem->fState & MFS_DEFAULT )
1365 hfontOld = SelectObject( hdc, hMenuFontBold);
1370 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1371 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1372 i = strlenW( lpitem->text );
1376 for (i = 0; lpitem->text[i]; i++)
1377 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1381 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1383 if (!(lpitem->fState & MF_HILITE) )
1385 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1386 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1387 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1388 --rect.left; --rect.top; --rect.right; --rect.bottom;
1390 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1393 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
1395 /* paint the shortcut text */
1396 if (lpitem->text[i]) /* There's a tab or flush-right char */
1398 if (lpitem->text[i] == '\t')
1400 rect.left = lpitem->xTab;
1401 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1405 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1408 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1410 if (!(lpitem->fState & MF_HILITE) )
1412 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1413 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1414 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1415 --rect.left; --rect.top; --rect.right; --rect.bottom;
1417 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1419 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1423 SelectObject (hdc, hfontOld);
1428 /***********************************************************************
1429 * MENU_DrawPopupMenu
1431 * Paint a popup menu.
1433 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1435 HBRUSH hPrevBrush = 0;
1438 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1440 GetClientRect( hwnd, &rect );
1442 if(TWEAK_WineLook == WIN31_LOOK)
1444 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1445 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1448 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1449 && (SelectObject( hdc, hMenuFont)))
1453 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1455 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1461 /* draw 3-d shade */
1462 if(TWEAK_WineLook == WIN31_LOOK) {
1463 SelectObject( hdc, hShadeBrush );
1464 SetBkMode( hdc, TRANSPARENT );
1465 ropPrev = SetROP2( hdc, R2_MASKPEN );
1467 i = rect.right; /* why SetBrushOrg() doesn't? */
1468 PatBlt( hdc, i & 0xfffffffe,
1469 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1470 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1471 rect.bottom - rect.top, 0x00a000c9 );
1473 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1474 i & 0xfffffffe,rect.right - rect.left,
1475 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1476 SelectObject( hdc, hPrevPen );
1477 SelectObject( hdc, hPrevBrush );
1478 SetROP2( hdc, ropPrev );
1481 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1483 /* draw menu items */
1485 menu = MENU_GetMenu( hmenu );
1486 if (menu && menu->nItems)
1491 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1492 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1493 menu->Height, FALSE, ODA_DRAWENTIRE );
1498 SelectObject( hdc, hPrevBrush );
1503 /***********************************************************************
1506 * Paint a menu bar. Returns the height of the menu bar.
1507 * called from [windows/nonclient.c]
1509 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1516 WND *wndPtr = WIN_FindWndPtr( hwnd );
1518 lppop = MENU_GetMenu ((HMENU)wndPtr->wIDmenu );
1519 if (lppop == NULL || lprect == NULL)
1521 retvalue = GetSystemMetrics(SM_CYMENU);
1525 TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1527 hfontOld = SelectObject( hDC, hMenuFont);
1529 if (lppop->Height == 0)
1530 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1532 lprect->bottom = lprect->top + lppop->Height;
1536 retvalue = lppop->Height;
1540 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1542 if (TWEAK_WineLook == WIN31_LOOK)
1544 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1545 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1546 LineTo( hDC, lprect->right, lprect->bottom );
1550 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1551 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1552 LineTo( hDC, lprect->right, lprect->bottom );
1555 if (lppop->nItems == 0)
1557 retvalue = GetSystemMetrics(SM_CYMENU);
1561 for (i = 0; i < lppop->nItems; i++)
1563 MENU_DrawMenuItem( hwnd, (HMENU)wndPtr->wIDmenu, hwnd,
1564 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
1566 retvalue = lppop->Height;
1570 SelectObject (hDC, hfontOld);
1572 WIN_ReleaseWndPtr(wndPtr);
1576 /***********************************************************************
1577 * MENU_PatchResidentPopup
1579 BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
1581 WND *pTPWnd = MENU_GetTopPopupWnd();
1587 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1588 checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTPWnd->hmemTaskQ,
1589 pTPWnd->owner ? pTPWnd->owner->hwndSelf : 0);
1591 switch( checkQueue )
1593 case 0: /* checkWnd is the new popup owner */
1596 pTPWnd->owner = checkWnd;
1597 if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
1598 hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
1602 case 0xFFFF: /* checkWnd is destroyed */
1603 if( pTPWnd->owner == checkWnd )
1604 pTPWnd->owner = NULL;
1605 MENU_ReleaseTopPopupWnd();
1608 default: /* checkQueue is exiting */
1609 if( pTPWnd->hmemTaskQ == checkQueue )
1611 hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
1612 hTask = TASK_GetNextTask( hTask );
1619 TDB* task = (TDB*)GlobalLock16( hTask );
1622 pTPWnd->hInstance = task->hInstance;
1623 pTPWnd->hmemTaskQ = task->hQueue;
1624 MENU_ReleaseTopPopupWnd();
1627 else WARN("failed to patch resident popup.\n");
1630 MENU_ReleaseTopPopupWnd();
1634 /***********************************************************************
1637 * Display a popup menu.
1639 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1640 INT x, INT y, INT xanchor, INT yanchor )
1643 WND *wndOwner = NULL;
1645 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1646 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1648 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1649 if (menu->FocusedItem != NO_SELECTED_ITEM)
1651 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1652 menu->FocusedItem = NO_SELECTED_ITEM;
1655 /* store the owner for DrawItem */
1656 menu->hwndOwner = hwndOwner;
1658 if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
1662 MENU_PopupMenuCalcSize( menu, hwndOwner );
1664 /* adjust popup menu pos so that it fits within the desktop */
1666 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1667 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1669 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1672 x -= width - xanchor;
1673 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1674 x = GetSystemMetrics(SM_CXSCREEN) - width;
1678 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1681 y -= height + yanchor;
1682 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1683 y = GetSystemMetrics(SM_CYSCREEN) - height;
1687 if( TWEAK_WineLook == WIN31_LOOK )
1689 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1690 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1693 /* NOTE: In Windows, top menu popup is not owned. */
1694 if (!pTopPopupWnd) /* create top level popup menu window */
1696 assert( uSubPWndLevel == 0 );
1698 pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1699 WS_POPUP, x, y, width, height,
1700 hwndOwner, 0, wndOwner->hInstance,
1704 WIN_ReleaseWndPtr(wndOwner);
1707 menu->hWnd = pTopPopupWnd->hwndSelf;
1708 MENU_ReleaseTopPopupWnd();
1713 /* create a new window for the submenu */
1715 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1716 WS_POPUP, x, y, width, height,
1717 hwndOwner, 0, wndOwner->hInstance,
1721 WIN_ReleaseWndPtr(wndOwner);
1725 else /* top level popup menu window already exists */
1727 WND *pTPWnd = MENU_GetTopPopupWnd();
1728 menu->hWnd = pTPWnd->hwndSelf;
1730 MENU_PatchResidentPopup( 0, wndOwner );
1731 SendMessageA( pTPWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);
1733 /* adjust its size */
1735 SetWindowPos( menu->hWnd, 0, x, y, width, height,
1736 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
1737 MENU_ReleaseTopPopupWnd();
1740 uSubPWndLevel++; /* menu level counter */
1742 /* Display the window */
1744 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1745 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1746 UpdateWindow( menu->hWnd );
1747 WIN_ReleaseWndPtr(wndOwner);
1754 /***********************************************************************
1757 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1758 BOOL sendMenuSelect, HMENU topmenu )
1763 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1765 lppop = MENU_GetMenu( hmenu );
1766 if ((!lppop) || (!lppop->nItems)) return;
1768 if (lppop->FocusedItem == wIndex) return;
1769 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1770 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1772 SelectObject( hdc, hMenuFont);
1774 /* Clear previous highlighted item */
1775 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1777 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1778 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1779 lppop->Height, !(lppop->wFlags & MF_POPUP),
1783 /* Highlight new item (if any) */
1784 lppop->FocusedItem = wIndex;
1785 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1787 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1788 lppop->items[wIndex].fState |= MF_HILITE;
1789 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1790 &lppop->items[wIndex], lppop->Height,
1791 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1795 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1796 SendMessageA( hwndOwner, WM_MENUSELECT,
1797 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1798 ip->fType | ip->fState | MF_MOUSESELECT |
1799 (lppop->wFlags & MF_SYSMENU)), hmenu);
1802 else if (sendMenuSelect) {
1805 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1806 POPUPMENU *ptm = (POPUPMENU *) USER_HEAP_LIN_ADDR( topmenu );
1807 MENUITEM *ip = &ptm->items[pos];
1808 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1809 ip->fType | ip->fState | MF_MOUSESELECT |
1810 (ptm->wFlags & MF_SYSMENU)), topmenu);
1814 ReleaseDC( lppop->hWnd, hdc );
1818 /***********************************************************************
1819 * MENU_MoveSelection
1821 * Moves currently selected item according to the offset parameter.
1822 * If there is no selection then it should select the last item if
1823 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1825 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1830 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1832 menu = MENU_GetMenu( hmenu );
1833 if ((!menu) || (!menu->items)) return;
1835 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1837 if( menu->nItems == 1 ) return; else
1838 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1840 if (!(menu->items[i].fType & MF_SEPARATOR))
1842 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1847 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1848 i >= 0 && i < menu->nItems ; i += offset)
1849 if (!(menu->items[i].fType & MF_SEPARATOR))
1851 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1857 /**********************************************************************
1860 * Set an item flags, id and text ptr. Called by InsertMenu() and
1863 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1866 LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1868 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1870 if (IS_STRING_ITEM(flags))
1874 flags |= MF_SEPARATOR;
1880 /* Item beginning with a backspace is a help item */
1886 if (!(text = HEAP_strdupW( SystemHeap, 0, str ))) return FALSE;
1890 else if (IS_BITMAP_ITEM(flags))
1891 item->text = (LPWSTR)(HBITMAP)LOWORD(str);
1892 else item->text = NULL;
1894 if (flags & MF_OWNERDRAW)
1895 item->dwItemData = (DWORD)str;
1897 item->dwItemData = 0;
1899 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1900 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1902 if (flags & MF_POPUP)
1904 POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1905 if (menu) menu->wFlags |= MF_POPUP;
1917 if (flags & MF_POPUP)
1918 item->hSubMenu = id;
1920 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1921 flags |= MF_POPUP; /* keep popup */
1923 item->fType = flags & TYPE_MASK;
1924 item->fState = (flags & STATE_MASK) &
1925 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1928 /* Don't call SetRectEmpty here! */
1931 if (prevText) HeapFree( SystemHeap, 0, prevText );
1933 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1938 /**********************************************************************
1941 * Insert a new item into a menu.
1943 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1948 if (!(menu = MENU_GetMenu(hMenu)))
1951 /* Find where to insert new item */
1953 if (flags & MF_BYPOSITION) {
1954 if (pos > menu->nItems)
1957 if (!MENU_FindItem( &hMenu, &pos, flags ))
1960 if (!(menu = MENU_GetMenu( hMenu )))
1965 /* Create new items array */
1967 newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1970 WARN("allocation failed\n" );
1973 if (menu->nItems > 0)
1975 /* Copy the old array into the new one */
1976 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1977 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1978 (menu->nItems-pos)*sizeof(MENUITEM) );
1979 HeapFree( SystemHeap, 0, menu->items );
1981 menu->items = newItems;
1983 memset( &newItems[pos], 0, sizeof(*newItems) );
1984 menu->Height = 0; /* force size recalculate */
1985 return &newItems[pos];
1989 /**********************************************************************
1990 * MENU_ParseResource
1992 * Parse a standard menu resource and add items to the menu.
1993 * Return a pointer to the end of the resource.
1995 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
2002 flags = GET_WORD(res);
2003 res += sizeof(WORD);
2004 if (!(flags & MF_POPUP))
2007 res += sizeof(WORD);
2009 if (!IS_STRING_ITEM(flags))
2010 ERR("not a string item %04x\n", flags );
2012 if (!unicode) res += strlen(str) + 1;
2013 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
2014 if (flags & MF_POPUP)
2016 HMENU hSubMenu = CreatePopupMenu();
2017 if (!hSubMenu) return NULL;
2018 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
2020 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
2021 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
2023 else /* Not a popup */
2025 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
2026 else AppendMenuW( hMenu, flags, id,
2027 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
2029 } while (!(flags & MF_END));
2034 /**********************************************************************
2035 * MENUEX_ParseResource
2037 * Parse an extended menu resource and add items to the menu.
2038 * Return a pointer to the end of the resource.
2040 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
2046 mii.cbSize = sizeof(mii);
2047 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
2048 mii.fType = GET_DWORD(res);
2049 res += sizeof(DWORD);
2050 mii.fState = GET_DWORD(res);
2051 res += sizeof(DWORD);
2052 mii.wID = GET_DWORD(res);
2053 res += sizeof(DWORD);
2054 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
2055 res += sizeof(WORD);
2056 /* Align the text on a word boundary. */
2057 res += (~((int)res - 1)) & 1;
2058 mii.dwTypeData = (LPWSTR) res;
2059 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2060 /* Align the following fields on a dword boundary. */
2061 res += (~((int)res - 1)) & 3;
2063 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2065 LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
2067 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2068 mii.fType, mii.fState, mii.wID, resinfo, newstr);
2069 HeapFree( GetProcessHeap(), 0, newstr );
2072 if (resinfo & 1) { /* Pop-up? */
2073 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2074 res += sizeof(DWORD);
2075 mii.hSubMenu = CreatePopupMenu();
2078 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2079 DestroyMenu(mii.hSubMenu);
2082 mii.fMask |= MIIM_SUBMENU;
2083 mii.fType |= MF_POPUP;
2085 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2086 } while (!(resinfo & MF_END));
2091 /***********************************************************************
2094 * Return the handle of the selected sub-popup menu (if any).
2096 static HMENU MENU_GetSubPopup( HMENU hmenu )
2101 menu = MENU_GetMenu( hmenu );
2103 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2105 item = &menu->items[menu->FocusedItem];
2106 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2107 return item->hSubMenu;
2112 /***********************************************************************
2113 * MENU_HideSubPopups
2115 * Hide the sub-popup menus of this menu.
2117 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2118 BOOL sendMenuSelect )
2120 POPUPMENU *menu = MENU_GetMenu( hmenu );
2122 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2124 if (menu && uSubPWndLevel)
2130 if (menu->FocusedItem != NO_SELECTED_ITEM)
2132 item = &menu->items[menu->FocusedItem];
2133 if (!(item->fType & MF_POPUP) ||
2134 !(item->fState & MF_MOUSESELECT)) return;
2135 item->fState &= ~MF_MOUSESELECT;
2136 hsubmenu = item->hSubMenu;
2139 submenu = MENU_GetMenu( hsubmenu );
2140 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2141 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2143 if (submenu->hWnd == MENU_GetTopPopupWnd()->hwndSelf )
2145 ShowWindow( submenu->hWnd, SW_HIDE );
2150 DestroyWindow( submenu->hWnd );
2153 MENU_ReleaseTopPopupWnd();
2158 /***********************************************************************
2161 * Display the sub-menu of the selected item of this menu.
2162 * Return the handle of the submenu, or hmenu if no submenu to display.
2164 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2165 BOOL selectFirst, UINT wFlags )
2173 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2175 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2177 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
2178 (menu->FocusedItem == NO_SELECTED_ITEM))
2180 WIN_ReleaseWndPtr(wndPtr);
2184 item = &menu->items[menu->FocusedItem];
2185 if (!(item->fType & MF_POPUP) ||
2186 (item->fState & (MF_GRAYED | MF_DISABLED)))
2188 WIN_ReleaseWndPtr(wndPtr);
2192 /* message must be sent before using item,
2193 because nearly everything may be changed by the application ! */
2195 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2196 if (!(wFlags & TPM_NONOTIFY))
2197 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2198 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2200 item = &menu->items[menu->FocusedItem];
2203 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2204 if (!(item->fState & MF_HILITE))
2206 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2207 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2209 SelectObject( hdc, hMenuFont);
2211 item->fState |= MF_HILITE;
2212 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2213 ReleaseDC( menu->hWnd, hdc );
2215 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2218 item->fState |= MF_MOUSESELECT;
2220 if (IS_SYSTEM_MENU(menu))
2222 MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, GetClassLongA(wndPtr->hwndSelf, GCL_STYLE));
2224 NC_GetSysPopupPos( wndPtr, &rect );
2225 rect.top = rect.bottom;
2226 rect.right = GetSystemMetrics(SM_CXSIZE);
2227 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2231 if (menu->wFlags & MF_POPUP)
2233 rect.left = wndPtr->rectWindow.left + item->rect.right - GetSystemMetrics(SM_CXBORDER);
2234 rect.top = wndPtr->rectWindow.top + item->rect.top;
2235 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2236 rect.bottom = item->rect.top - item->rect.bottom;
2240 rect.left = wndPtr->rectWindow.left + item->rect.left;
2241 rect.top = wndPtr->rectWindow.top + item->rect.bottom;
2242 rect.right = item->rect.right - item->rect.left;
2243 rect.bottom = item->rect.bottom - item->rect.top;
2247 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2248 rect.left, rect.top, rect.right, rect.bottom );
2250 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2251 WIN_ReleaseWndPtr(wndPtr);
2252 return item->hSubMenu;
2257 /**********************************************************************
2260 BOOL MENU_IsMenuActive(void)
2262 return pTopPopupWnd && (pTopPopupWnd->dwStyle & WS_VISIBLE);
2265 /***********************************************************************
2268 * Walks menu chain trying to find a menu pt maps to.
2270 static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2272 POPUPMENU *menu = MENU_GetMenu( hMenu );
2273 register UINT ht = menu->FocusedItem;
2275 /* try subpopup first (if any) */
2276 ht = (ht != NO_SELECTED_ITEM &&
2277 (menu->items[ht].fType & MF_POPUP) &&
2278 (menu->items[ht].fState & MF_MOUSESELECT))
2279 ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
2281 if( !ht ) /* check the current window (avoiding WM_HITTEST) */
2283 ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt );
2284 if( menu->wFlags & MF_POPUP )
2285 ht = (ht != (UINT)HTNOWHERE &&
2286 ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
2289 WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
2291 ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu)
2292 : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0;
2293 WIN_ReleaseWndPtr(wndPtr);
2299 /***********************************************************************
2300 * MENU_ExecFocusedItem
2302 * Execute a menu item (for instance when user pressed Enter).
2303 * Return the wID of the executed item. Otherwise, -1 indicating
2304 * that no menu item was executed;
2305 * Have to receive the flags for the TrackPopupMenu options to avoid
2306 * sending unwanted message.
2309 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2312 POPUPMENU *menu = MENU_GetMenu( hMenu );
2314 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2316 if (!menu || !menu->nItems ||
2317 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2319 item = &menu->items[menu->FocusedItem];
2321 TRACE("%08x %08x %08x\n",
2322 hMenu, item->wID, item->hSubMenu);
2324 if (!(item->fType & MF_POPUP))
2326 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2328 /* If TPM_RETURNCMD is set you return the id, but
2329 do not send a message to the owner */
2330 if(!(wFlags & TPM_RETURNCMD))
2332 if( menu->wFlags & MF_SYSMENU )
2333 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2334 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2336 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2342 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2347 /***********************************************************************
2348 * MENU_SwitchTracking
2350 * Helper function for menu navigation routines.
2352 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2354 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2355 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2357 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2359 if( pmt->hTopMenu != hPtMenu &&
2360 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2362 /* both are top level menus (system and menu-bar) */
2363 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2364 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2365 pmt->hTopMenu = hPtMenu;
2367 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2368 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2372 /***********************************************************************
2375 * Return TRUE if we can go on with menu tracking.
2377 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2379 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2384 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2387 if( IS_SYSTEM_MENU(ptmenu) )
2388 item = ptmenu->items;
2390 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2394 if( ptmenu->FocusedItem != id )
2395 MENU_SwitchTracking( pmt, hPtMenu, id );
2397 /* If the popup menu is not already "popped" */
2398 if(!(item->fState & MF_MOUSESELECT ))
2400 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2402 /* In win31, a newly popped menu always remains opened for the next buttonup */
2403 if(TWEAK_WineLook == WIN31_LOOK)
2404 ptmenu->bTimeToHide = FALSE;
2409 /* Else the click was on the menu bar, finish the tracking */
2414 /***********************************************************************
2417 * Return the value of MENU_ExecFocusedItem if
2418 * the selected item was not a popup. Else open the popup.
2419 * A -1 return value indicates that we go on with menu tracking.
2422 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2424 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2429 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2432 if( IS_SYSTEM_MENU(ptmenu) )
2433 item = ptmenu->items;
2435 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2437 if( item && (ptmenu->FocusedItem == id ))
2439 if( !(item->fType & MF_POPUP) )
2440 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2442 /* If we are dealing with the top-level menu */
2443 /* and this is a click on an already "popped" item: */
2444 /* Stop the menu tracking and close the opened submenus */
2445 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2448 ptmenu->bTimeToHide = TRUE;
2454 /***********************************************************************
2457 * Return TRUE if we can go on with menu tracking.
2459 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2461 UINT id = NO_SELECTED_ITEM;
2462 POPUPMENU *ptmenu = NULL;
2466 ptmenu = MENU_GetMenu( hPtMenu );
2467 if( IS_SYSTEM_MENU(ptmenu) )
2470 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2473 if( id == NO_SELECTED_ITEM )
2475 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2476 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2479 else if( ptmenu->FocusedItem != id )
2481 MENU_SwitchTracking( pmt, hPtMenu, id );
2482 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2488 /***********************************************************************
2491 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2493 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2495 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2497 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2498 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2504 LRESULT l = SendMessageA( pmt->hOwnerWnd, WM_NEXTMENU, vk,
2505 (IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
2507 TRACE("%04x [%04x] -> %04x [%04x]\n",
2508 (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
2512 wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
2514 hNewWnd = pmt->hOwnerWnd;
2515 if( IS_SYSTEM_MENU(menu) )
2517 /* switch to the menu bar */
2519 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
2521 WIN_ReleaseWndPtr(wndPtr);
2525 hNewMenu = wndPtr->wIDmenu;
2528 menu = MENU_GetMenu( hNewMenu );
2529 id = menu->nItems - 1;
2532 else if( wndPtr->dwStyle & WS_SYSMENU )
2534 /* switch to the system menu */
2535 hNewMenu = wndPtr->hSysMenu;
2539 WIN_ReleaseWndPtr(wndPtr);
2542 WIN_ReleaseWndPtr(wndPtr);
2544 else /* application returned a new menu to switch to */
2546 hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
2548 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2550 wndPtr = WIN_FindWndPtr(hNewWnd);
2552 if( wndPtr->dwStyle & WS_SYSMENU &&
2553 GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
2555 /* get the real system menu */
2556 hNewMenu = wndPtr->hSysMenu;
2558 else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
2560 /* FIXME: Not sure what to do here;
2561 * perhaps try to track hNewMenu as a popup? */
2563 TRACE(" -- got confused.\n");
2564 WIN_ReleaseWndPtr(wndPtr);
2567 WIN_ReleaseWndPtr(wndPtr);
2572 if( hNewMenu != pmt->hTopMenu )
2574 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2576 if( pmt->hCurrentMenu != pmt->hTopMenu )
2577 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2580 if( hNewWnd != pmt->hOwnerWnd )
2583 pmt->hOwnerWnd = hNewWnd;
2584 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2587 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2588 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2595 /***********************************************************************
2598 * The idea is not to show the popup if the next input message is
2599 * going to hide it anyway.
2601 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2605 msg.hwnd = pmt->hOwnerWnd;
2607 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2608 pmt->trackFlags |= TF_SKIPREMOVE;
2613 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2614 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2616 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2617 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2618 if( msg.message == WM_KEYDOWN &&
2619 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2621 pmt->trackFlags |= TF_SUSPENDPOPUP;
2628 /* failures go through this */
2629 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2633 /***********************************************************************
2636 * Handle a VK_LEFT key event in a menu.
2638 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2641 HMENU hmenutmp, hmenuprev;
2644 hmenuprev = hmenutmp = pmt->hTopMenu;
2645 menu = MENU_GetMenu( hmenutmp );
2647 /* Try to move 1 column left (if possible) */
2648 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2649 NO_SELECTED_ITEM ) {
2651 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2656 /* close topmost popup */
2657 while (hmenutmp != pmt->hCurrentMenu)
2659 hmenuprev = hmenutmp;
2660 hmenutmp = MENU_GetSubPopup( hmenuprev );
2663 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2664 pmt->hCurrentMenu = hmenuprev;
2666 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2668 /* move menu bar selection if no more popups are left */
2670 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2671 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2673 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2675 /* A sublevel menu was displayed - display the next one
2676 * unless there is another displacement coming up */
2678 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2679 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2680 pmt->hTopMenu, TRUE, wFlags);
2686 /***********************************************************************
2689 * Handle a VK_RIGHT key event in a menu.
2691 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2694 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2697 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2699 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->
2701 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2703 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2705 /* If already displaying a popup, try to display sub-popup */
2707 hmenutmp = pmt->hCurrentMenu;
2708 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2710 /* if subpopup was displayed then we are done */
2711 if (hmenutmp != pmt->hCurrentMenu) return;
2714 /* Check to see if there's another column */
2715 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2716 NO_SELECTED_ITEM ) {
2717 TRACE("Going to %d.\n", nextcol );
2718 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2723 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2725 if( pmt->hCurrentMenu != pmt->hTopMenu )
2727 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2728 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2729 } else hmenutmp = 0;
2731 /* try to move to the next item */
2732 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2733 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2735 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2736 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2737 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2738 pmt->hTopMenu, TRUE, wFlags);
2742 /***********************************************************************
2745 * Menu tracking code.
2747 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2748 HWND hwnd, const RECT *lprect )
2753 INT executedMenuId = -1;
2755 BOOL enterIdleSent = FALSE;
2758 mt.hCurrentMenu = hmenu;
2759 mt.hTopMenu = hmenu;
2760 mt.hOwnerWnd = hwnd;
2764 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2765 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2766 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2769 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2771 if (wFlags & TPM_BUTTONDOWN)
2773 /* Get the result in order to start the tracking or not */
2774 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2775 fEndMenu = !fRemove;
2778 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2782 menu = MENU_GetMenu( mt.hCurrentMenu );
2783 msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2785 /* we have to keep the message in the queue until it's
2786 * clear that menu loop is not over yet. */
2788 if (!MSG_InternalGetMessage( QMSG_WIN32A, &msg, msg.hwnd, mt.hOwnerWnd,
2789 MSGF_MENU, PM_NOREMOVE, !enterIdleSent, &enterIdleSent )) break;
2791 /* check if EndMenu() tried to cancel us, by posting this message */
2792 if(msg.message == WM_CANCELMODE)
2794 /* we are now out of the loop */
2797 /* remove the message from the queue */
2798 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2800 /* break out of internal loop, ala ESCAPE */
2804 TranslateMessage( &msg );
2807 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2808 enterIdleSent=FALSE;
2811 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2814 * use the mouse coordinates in lParam instead of those in the MSG
2815 * struct to properly handle synthetic messages. lParam coords are
2816 * relative to client area, so they must be converted; since they can
2817 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2819 mt.pt.x = SLOWORD(msg.lParam);
2820 mt.pt.y = SHIWORD(msg.lParam);
2821 ClientToScreen(msg.hwnd,&mt.pt);
2823 /* Find a menu for this mouse event */
2824 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2828 /* no WM_NC... messages in captured state */
2830 case WM_RBUTTONDBLCLK:
2831 case WM_RBUTTONDOWN:
2832 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2834 case WM_LBUTTONDBLCLK:
2835 case WM_LBUTTONDOWN:
2836 /* If the message belongs to the menu, removes it from the queue */
2837 /* Else, end menu tracking */
2838 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2839 fEndMenu = !fRemove;
2843 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2846 /* Check if a menu was selected by the mouse */
2849 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2851 /* End the loop if executedMenuId is an item ID */
2852 /* or if the job was done (executedMenuId = 0). */
2853 fEndMenu = fRemove = (executedMenuId != -1);
2855 /* No menu was selected by the mouse */
2856 /* if the function was called by TrackPopupMenu, continue
2857 with the menu tracking. If not, stop it */
2859 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2864 /* In win95 winelook, the selected menu item must be changed every time the
2865 mouse moves. In Win31 winelook, the mouse button has to be held down */
2867 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2868 ( (msg.wParam & MK_LBUTTON) ||
2869 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2871 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2873 } /* switch(msg.message) - mouse */
2875 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2877 fRemove = TRUE; /* Keyboard messages are always removed */
2885 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2886 NO_SELECTED_ITEM, FALSE, 0 );
2889 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2890 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2893 case VK_DOWN: /* If on menu bar, pull-down the menu */
2895 menu = MENU_GetMenu( mt.hCurrentMenu );
2896 if (!(menu->wFlags & MF_POPUP))
2897 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2898 else /* otherwise try to move selection */
2899 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2903 MENU_KeyLeft( &mt, wFlags );
2907 MENU_KeyRight( &mt, wFlags );
2917 hi.cbSize = sizeof(HELPINFO);
2918 hi.iContextType = HELPINFO_MENUITEM;
2919 if (menu->FocusedItem == NO_SELECTED_ITEM)
2922 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2923 hi.hItemHandle = hmenu;
2924 hi.dwContextId = menu->dwContextHelpID;
2925 hi.MousePos = msg.pt;
2926 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2933 break; /* WM_KEYDOWN */
2943 break; /* WM_SYSKEYDOWN */
2949 if (msg.wParam == '\r' || msg.wParam == ' ')
2951 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2952 fEndMenu = (executedMenuId != -1);
2957 /* Hack to avoid control chars. */
2958 /* We will find a better way real soon... */
2959 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2961 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
2962 LOWORD(msg.wParam), FALSE );
2963 if (pos == (UINT)-2) fEndMenu = TRUE;
2964 else if (pos == (UINT)-1) MessageBeep(0);
2967 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2969 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2970 fEndMenu = (executedMenuId != -1);
2974 } /* switch(msg.message) - kbd */
2978 DispatchMessageA( &msg );
2981 if (!fEndMenu) fRemove = TRUE;
2983 /* finally remove message from the queue */
2985 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2986 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2987 else mt.trackFlags &= ~TF_SKIPREMOVE;
2992 /* If dropdown is still painted and the close box is clicked on
2993 then the menu will be destroyed as part of the DispatchMessage above.
2994 This will then invalidate the menu handle in mt.hTopMenu. We should
2995 check for this first. */
2996 if( IsMenu( mt.hTopMenu ) )
2998 menu = MENU_GetMenu( mt.hTopMenu );
3000 if( IsWindow( mt.hOwnerWnd ) )
3002 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
3004 if (menu && menu->wFlags & MF_POPUP)
3006 ShowWindow( menu->hWnd, SW_HIDE );
3009 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3010 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
3013 /* Reset the variable for hiding menu */
3014 if( menu ) menu->bTimeToHide = FALSE;
3017 /* The return value is only used by TrackPopupMenu */
3018 return ((executedMenuId != -1) ? executedMenuId : 0);
3021 /***********************************************************************
3024 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
3026 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
3030 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3031 if (!(wFlags & TPM_NONOTIFY))
3032 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
3034 SendMessageA( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
3036 if (!(wFlags & TPM_NONOTIFY))
3037 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
3041 /***********************************************************************
3044 static BOOL MENU_ExitTracking(HWND hWnd)
3046 TRACE("hwnd=0x%04x\n", hWnd);
3048 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
3053 /***********************************************************************
3054 * MENU_TrackMouseMenuBar
3056 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3058 void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt )
3060 HWND hWnd = wndPtr->hwndSelf;
3061 HMENU hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
3062 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3064 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr, ht, pt.x, pt.y);
3068 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
3069 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
3070 MENU_ExitTracking(hWnd);
3075 /***********************************************************************
3076 * MENU_TrackKbdMenuBar
3078 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3080 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
3082 UINT uItem = NO_SELECTED_ITEM;
3084 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3086 /* find window that has a menu */
3088 while( wndPtr->dwStyle & WS_CHILD)
3089 if( !(wndPtr = wndPtr->parent) ) return;
3091 /* check if we have to track a system menu */
3093 if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) ||
3094 !wndPtr->wIDmenu || vkey == VK_SPACE )
3096 if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
3097 hTrackMenu = wndPtr->hSysMenu;
3099 wParam |= HTSYSMENU; /* prevent item lookup */
3102 hTrackMenu = wndPtr->wIDmenu;
3104 if (IsMenu( hTrackMenu ))
3106 MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu, FALSE, wFlags );
3108 if( vkey && vkey != VK_SPACE )
3110 uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu,
3111 vkey, (wParam & HTSYSMENU) );
3112 if( uItem >= (UINT)(-2) )
3114 if( uItem == (UINT)(-1) ) MessageBeep(0);
3121 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE, 0 );
3123 if( uItem == NO_SELECTED_ITEM )
3124 MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
3126 PostMessageA( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
3128 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, wndPtr->hwndSelf, NULL );
3131 MENU_ExitTracking (wndPtr->hwndSelf);
3136 /**********************************************************************
3137 * TrackPopupMenu16 (USER.416)
3139 BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
3140 INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
3144 CONV_RECT16TO32( lpRect, &r );
3145 return TrackPopupMenu( hMenu, wFlags, x, y, nReserved, hWnd,
3146 lpRect ? &r : NULL );
3150 /**********************************************************************
3151 * TrackPopupMenu (USER32.549)
3153 * Like the win32 API, the function return the command ID only if the
3154 * flag TPM_RETURNCMD is on.
3157 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3158 INT nReserved, HWND hWnd, const RECT *lpRect )
3162 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3164 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3165 if (!(wFlags & TPM_NONOTIFY))
3166 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3168 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3169 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3170 MENU_ExitTracking(hWnd);
3172 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3178 /**********************************************************************
3179 * TrackPopupMenuEx (USER32.550)
3181 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3182 HWND hWnd, LPTPMPARAMS lpTpm )
3184 FIXME("not fully implemented\n" );
3185 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3186 lpTpm ? &lpTpm->rcExclude : NULL );
3189 /***********************************************************************
3192 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3194 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3196 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3197 hwnd, message, wParam, lParam);
3203 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3204 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3208 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3209 return MA_NOACTIVATE;
3214 BeginPaint( hwnd, &ps );
3215 MENU_DrawPopupMenu( hwnd, ps.hdc,
3216 (HMENU)GetWindowLongA( hwnd, 0 ) );
3217 EndPaint( hwnd, &ps );
3225 /* zero out global pointer in case resident popup window
3226 * was somehow destroyed. */
3228 if(MENU_GetTopPopupWnd() )
3230 if( hwnd == pTopPopupWnd->hwndSelf )
3232 ERR("resident popup destroyed!\n");
3234 MENU_DestroyTopPopupWnd();
3239 MENU_ReleaseTopPopupWnd();
3247 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
3250 SetWindowLongW( hwnd, 0, 0 );
3253 case MM_SETMENUHANDLE:
3254 SetWindowLongW( hwnd, 0, wParam );
3257 case MM_GETMENUHANDLE:
3258 return GetWindowLongW( hwnd, 0 );
3261 return DefWindowProcW( hwnd, message, wParam, lParam );
3267 /***********************************************************************
3268 * MENU_GetMenuBarHeight
3270 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3272 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3273 INT orgX, INT orgY )
3281 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3282 hwnd, menubarWidth, orgX, orgY );
3284 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
3287 if (!(lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu)))
3289 WIN_ReleaseWndPtr(wndPtr);
3293 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3294 SelectObject( hdc, hMenuFont);
3295 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3296 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3297 ReleaseDC( hwnd, hdc );
3298 retvalue = lppop->Height;
3299 WIN_ReleaseWndPtr(wndPtr);
3304 /*******************************************************************
3305 * ChangeMenu16 (USER.153)
3307 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3308 UINT16 id, UINT16 flags )
3310 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3311 hMenu, pos, (DWORD)data, id, flags );
3312 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3315 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3316 /* for MF_DELETE. We should check the parameters for all others */
3317 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3319 if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3320 if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3322 if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
3323 flags & MF_BYPOSITION ? pos : id,
3324 flags & ~MF_REMOVE );
3325 /* Default: MF_INSERT */
3326 return InsertMenu16( hMenu, pos, flags, id, data );
3330 /*******************************************************************
3331 * ChangeMenuA (USER32.23)
3333 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3334 UINT id, UINT flags )
3336 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3337 hMenu, pos, (DWORD)data, id, flags );
3338 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3340 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3341 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3343 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3344 flags & MF_BYPOSITION ? pos : id,
3345 flags & ~MF_REMOVE );
3346 /* Default: MF_INSERT */
3347 return InsertMenuA( hMenu, pos, flags, id, data );
3351 /*******************************************************************
3352 * ChangeMenuW (USER32.24)
3354 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3355 UINT id, UINT flags )
3357 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3358 hMenu, pos, (DWORD)data, id, flags );
3359 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3361 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3362 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3364 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3365 flags & MF_BYPOSITION ? pos : id,
3366 flags & ~MF_REMOVE );
3367 /* Default: MF_INSERT */
3368 return InsertMenuW( hMenu, pos, flags, id, data );
3372 /*******************************************************************
3373 * CheckMenuItem16 (USER.154)
3375 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
3377 return (BOOL16)CheckMenuItem( hMenu, id, flags );
3381 /*******************************************************************
3382 * CheckMenuItem (USER32.46)
3384 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3389 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3390 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3391 ret = item->fState & MF_CHECKED;
3392 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3393 else item->fState &= ~MF_CHECKED;
3398 /**********************************************************************
3399 * EnableMenuItem16 (USER.155)
3401 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3403 return EnableMenuItem( hMenu, wItemID, wFlags );
3407 /**********************************************************************
3408 * EnableMenuItem (USER32.170)
3410 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3416 TRACE("(%04x, %04X, %04X) !\n",
3417 hMenu, wItemID, wFlags);
3419 /* Get the Popupmenu to access the owner menu */
3420 if (!(menu = MENU_GetMenu(hMenu)))
3423 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3426 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3427 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3429 /* In win95 if the close item in the system menu change update the close button */
3430 if (TWEAK_WineLook == WIN95_LOOK)
3431 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3433 if (menu->hSysMenuOwner != 0)
3435 POPUPMENU* parentMenu;
3437 /* Get the parent menu to access*/
3438 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3441 /* Refresh the frame to reflect the change*/
3442 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3443 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3451 /*******************************************************************
3452 * GetMenuString16 (USER.161)
3454 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3455 LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
3457 return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
3461 /*******************************************************************
3462 * GetMenuStringA (USER32.268)
3464 INT WINAPI GetMenuStringA(
3465 HMENU hMenu, /* [in] menuhandle */
3466 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3467 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3468 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3469 UINT wFlags /* [in] MF_ flags */
3473 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3474 hMenu, wItemID, str, nMaxSiz, wFlags );
3475 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3476 if (!IS_STRING_ITEM(item->fType)) return 0;
3477 if (!str || !nMaxSiz) return strlenW(item->text);
3479 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3481 TRACE("returning '%s'\n", str );
3486 /*******************************************************************
3487 * GetMenuStringW (USER32.269)
3489 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3490 LPWSTR str, INT nMaxSiz, UINT wFlags )
3494 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3495 hMenu, wItemID, str, nMaxSiz, wFlags );
3496 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3497 if (!IS_STRING_ITEM(item->fType)) return 0;
3498 if (!str || !nMaxSiz) return strlenW(item->text);
3500 lstrcpynW( str, item->text, nMaxSiz );
3501 return strlenW(str);
3505 /**********************************************************************
3506 * HiliteMenuItem16 (USER.162)
3508 BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
3511 return HiliteMenuItem( hWnd, hMenu, wItemID, wHilite );
3515 /**********************************************************************
3516 * HiliteMenuItem (USER32.318)
3518 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3522 TRACE("(%04x, %04x, %04x, %04x);\n",
3523 hWnd, hMenu, wItemID, wHilite);
3524 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3525 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3526 if (menu->FocusedItem == wItemID) return TRUE;
3527 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3528 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3533 /**********************************************************************
3534 * GetMenuState16 (USER.250)
3536 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3538 return GetMenuState( hMenu, wItemID, wFlags );
3542 /**********************************************************************
3543 * GetMenuState (USER32.267)
3545 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3548 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3549 hMenu, wItemID, wFlags);
3550 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3551 debug_print_menuitem (" item: ", item, "");
3552 if (item->fType & MF_POPUP)
3554 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3555 if (!menu) return -1;
3556 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3560 /* We used to (from way back then) mask the result to 0xff. */
3561 /* I don't know why and it seems wrong as the documented */
3562 /* return flag MF_SEPARATOR is outside that mask. */
3563 return (item->fType | item->fState);
3568 /**********************************************************************
3569 * GetMenuItemCount16 (USER.263)
3571 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3573 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3574 if (!menu) return -1;
3575 TRACE("(%04x) returning %d\n",
3576 hMenu, menu->nItems );
3577 return menu->nItems;
3581 /**********************************************************************
3582 * GetMenuItemCount (USER32.262)
3584 INT WINAPI GetMenuItemCount( HMENU hMenu )
3586 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3587 if (!menu) return -1;
3588 TRACE("(%04x) returning %d\n",
3589 hMenu, menu->nItems );
3590 return menu->nItems;
3593 /**********************************************************************
3594 * GetMenuItemID16 (USER.264)
3596 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3598 return (UINT16) GetMenuItemID (hMenu, nPos);
3601 /**********************************************************************
3602 * GetMenuItemID (USER32.263)
3604 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3608 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3609 if (lpmi->fType & MF_POPUP) return -1;
3614 /*******************************************************************
3615 * InsertMenu16 (USER.410)
3617 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3618 UINT16 id, SEGPTR data )
3620 UINT pos32 = (UINT)pos;
3621 if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3622 if (IS_STRING_ITEM(flags) && data)
3623 return InsertMenuA( hMenu, pos32, flags, id, MapSL(data) );
3624 return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3628 /*******************************************************************
3629 * InsertMenuW (USER32.325)
3631 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3632 UINT id, LPCWSTR str )
3636 if (IS_STRING_ITEM(flags) && str)
3637 TRACE("hMenu %04x, pos %d, flags %08x, "
3638 "id %04x, str '%s'\n",
3639 hMenu, pos, flags, id, debugstr_w(str) );
3640 else TRACE("hMenu %04x, pos %d, flags %08x, "
3641 "id %04x, str %08lx (not a string)\n",
3642 hMenu, pos, flags, id, (DWORD)str );
3644 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3646 if (!(MENU_SetItemData( item, flags, id, str )))
3648 RemoveMenu( hMenu, pos, flags );
3652 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3653 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3655 item->hCheckBit = item->hUnCheckBit = 0;
3660 /*******************************************************************
3661 * InsertMenuA (USER32.322)
3663 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3664 UINT id, LPCSTR str )
3668 if (IS_STRING_ITEM(flags) && str)
3670 LPWSTR newstr = HEAP_strdupAtoW( GetProcessHeap(), 0, str );
3671 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3672 HeapFree( GetProcessHeap(), 0, newstr );
3675 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3679 /*******************************************************************
3680 * AppendMenu16 (USER.411)
3682 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3684 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3688 /*******************************************************************
3689 * AppendMenuA (USER32.5)
3691 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3692 UINT id, LPCSTR data )
3694 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3698 /*******************************************************************
3699 * AppendMenuW (USER32.6)
3701 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3702 UINT id, LPCWSTR data )
3704 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3708 /**********************************************************************
3709 * RemoveMenu16 (USER.412)
3711 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3713 return RemoveMenu( hMenu, nPos, wFlags );
3717 /**********************************************************************
3718 * RemoveMenu (USER32.441)
3720 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3725 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3726 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3727 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3731 MENU_FreeItemData( item );
3733 if (--menu->nItems == 0)
3735 HeapFree( SystemHeap, 0, menu->items );
3740 while(nPos < menu->nItems)
3746 menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
3747 menu->nItems * sizeof(MENUITEM) );
3753 /**********************************************************************
3754 * DeleteMenu16 (USER.413)
3756 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3758 return DeleteMenu( hMenu, nPos, wFlags );
3762 /**********************************************************************
3763 * DeleteMenu (USER32.129)
3765 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3767 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3768 if (!item) return FALSE;
3769 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3770 /* nPos is now the position of the item */
3771 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3776 /*******************************************************************
3777 * ModifyMenu16 (USER.414)
3779 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3780 UINT16 id, SEGPTR data )
3782 if (IS_STRING_ITEM(flags))
3783 return ModifyMenuA( hMenu, pos, flags, id, MapSL(data) );
3784 return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3788 /*******************************************************************
3789 * ModifyMenuW (USER32.398)
3791 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3792 UINT id, LPCWSTR str )
3796 if (IS_STRING_ITEM(flags))
3798 TRACE("%04x %d %04x %04x '%s'\n",
3799 hMenu, pos, flags, id, str ? debugstr_w(str) : "#NULL#" );
3800 if (!str) return FALSE;
3804 TRACE("%04x %d %04x %04x %08lx\n",
3805 hMenu, pos, flags, id, (DWORD)str );
3808 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3809 return MENU_SetItemData( item, flags, id, str );
3813 /*******************************************************************
3814 * ModifyMenuA (USER32.397)
3816 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3817 UINT id, LPCSTR str )
3821 if (IS_STRING_ITEM(flags) && str)
3823 LPWSTR newstr = HEAP_strdupAtoW( GetProcessHeap(), 0, str );
3824 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3825 HeapFree( GetProcessHeap(), 0, newstr );
3828 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3832 /**********************************************************************
3833 * CreatePopupMenu16 (USER.415)
3835 HMENU16 WINAPI CreatePopupMenu16(void)
3837 return CreatePopupMenu();
3841 /**********************************************************************
3842 * CreatePopupMenu (USER32.82)
3844 HMENU WINAPI CreatePopupMenu(void)
3849 if (!(hmenu = CreateMenu())) return 0;
3850 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
3851 menu->wFlags |= MF_POPUP;
3852 menu->bTimeToHide = FALSE;
3857 /**********************************************************************
3858 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3860 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3862 return MAKELONG( check_bitmap_width, check_bitmap_height );
3866 /**********************************************************************
3867 * SetMenuItemBitmaps16 (USER.418)
3869 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3870 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3872 return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3876 /**********************************************************************
3877 * SetMenuItemBitmaps (USER32.490)
3879 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3880 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3883 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3884 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3885 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3887 if (!hNewCheck && !hNewUnCheck)
3889 item->fState &= ~MF_USECHECKBITMAPS;
3891 else /* Install new bitmaps */
3893 item->hCheckBit = hNewCheck;
3894 item->hUnCheckBit = hNewUnCheck;
3895 item->fState |= MF_USECHECKBITMAPS;
3901 /**********************************************************************
3902 * CreateMenu16 (USER.151)
3904 HMENU16 WINAPI CreateMenu16(void)
3906 return CreateMenu();
3910 /**********************************************************************
3911 * CreateMenu (USER32.81)
3913 HMENU WINAPI CreateMenu(void)
3917 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3918 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3920 ZeroMemory(menu, sizeof(POPUPMENU));
3921 menu->wMagic = MENU_MAGIC;
3922 menu->FocusedItem = NO_SELECTED_ITEM;
3923 menu->bTimeToHide = FALSE;
3925 TRACE("return %04x\n", hMenu );
3931 /**********************************************************************
3932 * DestroyMenu16 (USER.152)
3934 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3936 return DestroyMenu( hMenu );
3940 /**********************************************************************
3941 * DestroyMenu (USER32.134)
3943 BOOL WINAPI DestroyMenu( HMENU hMenu )
3945 TRACE("(%04x)\n", hMenu);
3947 /* Silently ignore attempts to destroy default system popup */
3949 if (hMenu && hMenu != MENU_DefSysPopup)
3951 LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3952 WND *pTPWnd = MENU_GetTopPopupWnd();
3954 if( pTPWnd && (hMenu == *(HMENU*)pTPWnd->wExtra) )
3955 *(UINT*)pTPWnd->wExtra = 0;
3957 if (!IS_A_MENU(lppop)) lppop = NULL;
3960 lppop->wMagic = 0; /* Mark it as destroyed */
3962 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
3963 (!pTPWnd || (lppop->hWnd != pTPWnd->hwndSelf)))
3964 DestroyWindow( lppop->hWnd );
3966 if (lppop->items) /* recursively destroy submenus */
3969 MENUITEM *item = lppop->items;
3970 for (i = lppop->nItems; i > 0; i--, item++)
3972 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3973 MENU_FreeItemData( item );
3975 HeapFree( SystemHeap, 0, lppop->items );
3977 USER_HEAP_FREE( hMenu );
3978 MENU_ReleaseTopPopupWnd();
3982 MENU_ReleaseTopPopupWnd();
3986 return (hMenu != MENU_DefSysPopup);
3990 /**********************************************************************
3991 * GetSystemMenu16 (USER.156)
3993 HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
3995 return GetSystemMenu( hWnd, bRevert );
3999 /**********************************************************************
4000 * GetSystemMenu (USER32.291)
4002 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
4004 WND *wndPtr = WIN_FindWndPtr( hWnd );
4009 if( wndPtr->hSysMenu )
4013 DestroyMenu(wndPtr->hSysMenu);
4014 wndPtr->hSysMenu = 0;
4018 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
4021 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
4022 menu->items[0].hSubMenu = MENU_CopySysPopup();
4026 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
4027 wndPtr->hSysMenu, hWnd);
4028 wndPtr->hSysMenu = 0;
4033 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
4034 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
4036 if( wndPtr->hSysMenu )
4039 retvalue = GetSubMenu16(wndPtr->hSysMenu, 0);
4041 /* Store the dummy sysmenu handle to facilitate the refresh */
4042 /* of the close button if the SC_CLOSE item change */
4043 menu = MENU_GetMenu(retvalue);
4045 menu->hSysMenuOwner = wndPtr->hSysMenu;
4047 WIN_ReleaseWndPtr(wndPtr);
4049 return bRevert ? 0 : retvalue;
4053 /*******************************************************************
4054 * SetSystemMenu16 (USER.280)
4056 BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
4058 return SetSystemMenu( hwnd, hMenu );
4062 /*******************************************************************
4063 * SetSystemMenu (USER32.508)
4065 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
4067 WND *wndPtr = WIN_FindWndPtr(hwnd);
4071 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
4072 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
4073 WIN_ReleaseWndPtr(wndPtr);
4080 /**********************************************************************
4081 * GetMenu16 (USER.157)
4083 HMENU16 WINAPI GetMenu16( HWND16 hWnd )
4085 return (HMENU16)GetMenu(hWnd);
4089 /**********************************************************************
4090 * GetMenu (USER32.257)
4092 HMENU WINAPI GetMenu( HWND hWnd )
4095 WND * wndPtr = WIN_FindWndPtr(hWnd);
4097 if (!wndPtr) return 0;
4099 retvalue = (HMENU)wndPtr->wIDmenu;
4100 TRACE("for %swindow %04x returning %04x\n",
4101 (wndPtr->dwStyle & WS_CHILD) ? "child " : "", hWnd, retvalue);
4102 WIN_ReleaseWndPtr(wndPtr);
4107 /**********************************************************************
4108 * SetMenu16 (USER.158)
4110 BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
4112 return SetMenu( hWnd, hMenu );
4116 /**********************************************************************
4117 * SetMenu (USER32.487)
4119 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4121 WND * wndPtr = WIN_FindWndPtr(hWnd);
4124 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4126 if (hMenu && !IsMenu(hMenu))
4128 WARN("hMenu is not a menu handle\n");
4132 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4134 if (GetCapture() == hWnd) ReleaseCapture();
4136 wndPtr->wIDmenu = (UINT)hMenu;
4141 if (!(lpmenu = MENU_GetMenu(hMenu)))
4144 lpmenu->hWnd = hWnd;
4145 lpmenu->Height = 0; /* Make sure we recalculate the size */
4147 if (IsWindowVisible(hWnd))
4148 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4149 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4153 WIN_ReleaseWndPtr(wndPtr);
4159 /**********************************************************************
4160 * GetSubMenu16 (USER.159)
4162 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
4164 return GetSubMenu( hMenu, nPos );
4168 /**********************************************************************
4169 * GetSubMenu (USER32.288)
4171 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4175 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4176 if (!(lpmi->fType & MF_POPUP)) return 0;
4177 return lpmi->hSubMenu;
4181 /**********************************************************************
4182 * DrawMenuBar16 (USER.160)
4184 void WINAPI DrawMenuBar16( HWND16 hWnd )
4186 DrawMenuBar( hWnd );
4190 /**********************************************************************
4191 * DrawMenuBar (USER32.161)
4193 BOOL WINAPI DrawMenuBar( HWND hWnd )
4196 WND *wndPtr = WIN_FindWndPtr(hWnd);
4197 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
4199 lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu);
4202 WIN_ReleaseWndPtr(wndPtr);
4206 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4207 lppop->hwndOwner = hWnd;
4208 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4209 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4210 WIN_ReleaseWndPtr(wndPtr);
4213 WIN_ReleaseWndPtr(wndPtr);
4218 /***********************************************************************
4219 * EndMenu (USER.187) (USER32.175)
4221 void WINAPI EndMenu(void)
4223 /* if we are in the menu code, and it is active */
4224 if (fEndMenu == FALSE && MENU_IsMenuActive())
4226 /* terminate the menu handling code */
4229 /* needs to be posted to wakeup the internal menu handler */
4230 /* which will now terminate the menu, in the event that */
4231 /* the main window was minimized, or lost focus, so we */
4232 /* don't end up with an orphaned menu */
4233 PostMessageA( pTopPopupWnd->hwndSelf, WM_CANCELMODE, 0, 0);
4238 /***********************************************************************
4239 * LookupMenuHandle (USER.217)
4241 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4243 HMENU hmenu32 = hmenu;
4245 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4246 else return hmenu32;
4250 /**********************************************************************
4251 * LoadMenu16 (USER.150)
4253 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4259 TRACE("(%04x,%s)\n", instance, debugres_a(name) );
4263 if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4266 if (!name) return 0;
4268 /* check for Win32 module */
4269 if (HIWORD(instance)) return LoadMenuA( instance, name );
4270 instance = GetExePtr( instance );
4272 if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
4273 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4274 hMenu = LoadMenuIndirect16(LockResource16(handle));
4275 FreeResource16( handle );
4280 /*****************************************************************
4281 * LoadMenuA (USER32.370)
4283 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4285 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4286 if (!hrsrc) return 0;
4287 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4291 /*****************************************************************
4292 * LoadMenuW (USER32.373)
4294 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4296 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4297 if (!hrsrc) return 0;
4298 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4302 /**********************************************************************
4303 * LoadMenuIndirect16 (USER.220)
4305 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4308 WORD version, offset;
4309 LPCSTR p = (LPCSTR)template;
4311 TRACE("(%p)\n", template );
4312 version = GET_WORD(p);
4316 WARN("version must be 0 for Win16\n" );
4319 offset = GET_WORD(p);
4320 p += sizeof(WORD) + offset;
4321 if (!(hMenu = CreateMenu())) return 0;
4322 if (!MENU_ParseResource( p, hMenu, FALSE ))
4324 DestroyMenu( hMenu );
4331 /**********************************************************************
4332 * LoadMenuIndirectA (USER32.371)
4334 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4337 WORD version, offset;
4338 LPCSTR p = (LPCSTR)template;
4340 TRACE("%p\n", template );
4341 version = GET_WORD(p);
4346 offset = GET_WORD(p);
4347 p += sizeof(WORD) + offset;
4348 if (!(hMenu = CreateMenu())) return 0;
4349 if (!MENU_ParseResource( p, hMenu, TRUE ))
4351 DestroyMenu( hMenu );
4356 offset = GET_WORD(p);
4357 p += sizeof(WORD) + offset;
4358 if (!(hMenu = CreateMenu())) return 0;
4359 if (!MENUEX_ParseResource( p, hMenu))
4361 DestroyMenu( hMenu );
4366 ERR("version %d not supported.\n", version);
4372 /**********************************************************************
4373 * LoadMenuIndirectW (USER32.372)
4375 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4377 /* FIXME: is there anything different between A and W? */
4378 return LoadMenuIndirectA( template );
4382 /**********************************************************************
4383 * IsMenu16 (USER.358)
4385 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4387 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4388 return IS_A_MENU(menu);
4392 /**********************************************************************
4393 * IsMenu (USER32.346)
4395 BOOL WINAPI IsMenu(HMENU hmenu)
4397 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4398 return IS_A_MENU(menu);
4401 /**********************************************************************
4402 * GetMenuItemInfo_common
4405 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4406 LPMENUITEMINFOW lpmii, BOOL unicode)
4408 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4410 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4415 if (lpmii->fMask & MIIM_TYPE) {
4416 lpmii->fType = menu->fType;
4417 switch (MENU_ITEM_TYPE(menu->fType)) {
4419 break; /* will be done below */
4422 lpmii->dwTypeData = menu->text;
4429 /* copy the text string */
4430 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4431 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4436 len = strlenW(menu->text);
4437 if(lpmii->dwTypeData && lpmii->cch)
4438 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4442 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4443 if(lpmii->dwTypeData && lpmii->cch)
4444 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4445 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4446 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4448 /* if we've copied a substring we return its length */
4449 if(lpmii->dwTypeData && lpmii->cch)
4451 if (lpmii->cch <= len) lpmii->cch--;
4453 else /* return length of string */
4457 if (lpmii->fMask & MIIM_FTYPE)
4458 lpmii->fType = menu->fType;
4460 if (lpmii->fMask & MIIM_BITMAP)
4461 lpmii->hbmpItem = menu->hbmpItem;
4463 if (lpmii->fMask & MIIM_STATE)
4464 lpmii->fState = menu->fState;
4466 if (lpmii->fMask & MIIM_ID)
4467 lpmii->wID = menu->wID;
4469 if (lpmii->fMask & MIIM_SUBMENU)
4470 lpmii->hSubMenu = menu->hSubMenu;
4472 if (lpmii->fMask & MIIM_CHECKMARKS) {
4473 lpmii->hbmpChecked = menu->hCheckBit;
4474 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4476 if (lpmii->fMask & MIIM_DATA)
4477 lpmii->dwItemData = menu->dwItemData;
4482 /**********************************************************************
4483 * GetMenuItemInfoA (USER32.264)
4485 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4486 LPMENUITEMINFOA lpmii)
4488 return GetMenuItemInfo_common (hmenu, item, bypos,
4489 (LPMENUITEMINFOW)lpmii, FALSE);
4492 /**********************************************************************
4493 * GetMenuItemInfoW (USER32.265)
4495 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4496 LPMENUITEMINFOW lpmii)
4498 return GetMenuItemInfo_common (hmenu, item, bypos,
4502 /**********************************************************************
4503 * SetMenuItemInfo_common
4506 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4507 const MENUITEMINFOW *lpmii,
4510 if (!menu) return FALSE;
4512 if (lpmii->fMask & MIIM_TYPE ) {
4513 /* Get rid of old string. */
4514 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4515 HeapFree(SystemHeap, 0, menu->text);
4519 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4520 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4521 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4523 menu->text = lpmii->dwTypeData;
4525 if (IS_STRING_ITEM(menu->fType) && menu->text) {
4527 menu->text = HEAP_strdupW(SystemHeap, 0, lpmii->dwTypeData);
4529 menu->text = HEAP_strdupAtoW(SystemHeap, 0, (LPSTR)lpmii->dwTypeData);
4533 if (lpmii->fMask & MIIM_FTYPE ) {
4534 /* free the string when the type is changing */
4535 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4536 HeapFree(SystemHeap, 0, menu->text);
4539 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4540 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4543 if (lpmii->fMask & MIIM_STRING ) {
4544 /* free the string when used */
4545 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4546 HeapFree(SystemHeap, 0, menu->text);
4548 menu->text = HEAP_strdupW(SystemHeap, 0, lpmii->dwTypeData);
4550 menu->text = HEAP_strdupAtoW(SystemHeap, 0, (LPSTR) lpmii->dwTypeData);
4554 if (lpmii->fMask & MIIM_STATE)
4556 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4557 menu->fState = lpmii->fState;
4560 if (lpmii->fMask & MIIM_ID)
4561 menu->wID = lpmii->wID;
4563 if (lpmii->fMask & MIIM_SUBMENU) {
4564 menu->hSubMenu = lpmii->hSubMenu;
4565 if (menu->hSubMenu) {
4566 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4568 subMenu->wFlags |= MF_POPUP;
4569 menu->fType |= MF_POPUP;
4572 /* FIXME: Return an error ? */
4573 menu->fType &= ~MF_POPUP;
4576 menu->fType &= ~MF_POPUP;
4579 if (lpmii->fMask & MIIM_CHECKMARKS)
4581 if (lpmii->fType & MFT_RADIOCHECK)
4582 menu->fType |= MFT_RADIOCHECK;
4584 menu->hCheckBit = lpmii->hbmpChecked;
4585 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4587 if (lpmii->fMask & MIIM_DATA)
4588 menu->dwItemData = lpmii->dwItemData;
4590 debug_print_menuitem("SetMenuItemInfo_common: ", menu, "");
4594 /**********************************************************************
4595 * SetMenuItemInfoA (USER32.491)
4597 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4598 const MENUITEMINFOA *lpmii)
4600 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4601 (const MENUITEMINFOW *)lpmii, FALSE);
4604 /**********************************************************************
4605 * SetMenuItemInfoW (USER32.492)
4607 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4608 const MENUITEMINFOW *lpmii)
4610 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4614 /**********************************************************************
4615 * SetMenuDefaultItem (USER32.489)
4618 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4624 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4626 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4628 /* reset all default-item flags */
4630 for (i = 0; i < menu->nItems; i++, item++)
4632 item->fState &= ~MFS_DEFAULT;
4635 /* no default item */
4644 if ( uItem >= menu->nItems ) return FALSE;
4645 item[uItem].fState |= MFS_DEFAULT;
4650 for (i = 0; i < menu->nItems; i++, item++)
4652 if (item->wID == uItem)
4654 item->fState |= MFS_DEFAULT;
4663 /**********************************************************************
4664 * GetMenuDefaultItem (USER32.260)
4666 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4672 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4674 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4676 /* find default item */
4680 if (! item) return -1;
4682 while ( !( item->fState & MFS_DEFAULT ) )
4685 if (i >= menu->nItems ) return -1;
4688 /* default: don't return disabled items */
4689 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4691 /* search rekursiv when needed */
4692 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4695 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4696 if ( -1 != ret ) return ret;
4698 /* when item not found in submenu, return the popup item */
4700 return ( bypos ) ? i : item->wID;
4704 /*******************************************************************
4705 * InsertMenuItem16 (USER.441)
4709 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4710 const MENUITEMINFO16 *mii )
4714 miia.cbSize = sizeof(miia);
4715 miia.fMask = mii->fMask;
4716 miia.dwTypeData = (LPSTR)mii->dwTypeData;
4717 miia.fType = mii->fType;
4718 miia.fState = mii->fState;
4719 miia.wID = mii->wID;
4720 miia.hSubMenu = mii->hSubMenu;
4721 miia.hbmpChecked = mii->hbmpChecked;
4722 miia.hbmpUnchecked = mii->hbmpUnchecked;
4723 miia.dwItemData = mii->dwItemData;
4724 miia.cch = mii->cch;
4725 if (IS_STRING_ITEM(miia.fType))
4726 miia.dwTypeData = MapSL(mii->dwTypeData);
4727 return InsertMenuItemA( hmenu, pos, byposition, &miia );
4731 /**********************************************************************
4732 * InsertMenuItemA (USER32.323)
4734 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4735 const MENUITEMINFOA *lpmii)
4737 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4738 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4742 /**********************************************************************
4743 * InsertMenuItemW (USER32.324)
4745 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4746 const MENUITEMINFOW *lpmii)
4748 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4749 return SetMenuItemInfo_common(item, lpmii, TRUE);
4752 /**********************************************************************
4753 * CheckMenuRadioItem (USER32.47)
4756 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4757 UINT first, UINT last, UINT check,
4760 MENUITEM *mifirst, *milast, *micheck;
4761 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4763 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4764 hMenu, first, last, check, bypos);
4766 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4767 milast = MENU_FindItem (&mlast, &last, bypos);
4768 micheck = MENU_FindItem (&mcheck, &check, bypos);
4770 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4771 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4772 micheck > milast || micheck < mifirst)
4775 while (mifirst <= milast)
4777 if (mifirst == micheck)
4779 mifirst->fType |= MFT_RADIOCHECK;
4780 mifirst->fState |= MFS_CHECKED;
4782 mifirst->fType &= ~MFT_RADIOCHECK;
4783 mifirst->fState &= ~MFS_CHECKED;
4791 /**********************************************************************
4792 * CheckMenuRadioItem16 (not a Windows API)
4795 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4796 UINT16 first, UINT16 last, UINT16 check,
4799 return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4802 /**********************************************************************
4803 * GetMenuItemRect (USER32.266)
4805 * ATTENTION: Here, the returned values in rect are the screen
4806 * coordinates of the item just like if the menu was
4807 * always on the upper left side of the application.
4810 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4813 POPUPMENU *itemMenu;
4817 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4819 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4820 referenceHwnd = hwnd;
4824 itemMenu = MENU_GetMenu(hMenu);
4825 if (itemMenu == NULL)
4828 if(itemMenu->hWnd == 0)
4830 referenceHwnd = itemMenu->hWnd;
4833 if ((rect == NULL) || (item == NULL))
4838 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4843 /**********************************************************************
4844 * GetMenuItemRect16 (USER.665)
4847 BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
4853 if (!rect) return FALSE;
4854 res = GetMenuItemRect (hwnd, hMenu, uItem, &r32);
4855 CONV_RECT32TO16 (&r32, rect);
4859 /**********************************************************************
4863 * MIM_APPLYTOSUBMENUS
4864 * actually use the items to draw the menu
4866 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4870 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4872 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4875 if (lpmi->fMask & MIM_BACKGROUND)
4876 menu->hbrBack = lpmi->hbrBack;
4878 if (lpmi->fMask & MIM_HELPID)
4879 menu->dwContextHelpID = lpmi->dwContextHelpID;
4881 if (lpmi->fMask & MIM_MAXHEIGHT)
4882 menu->cyMax = lpmi->cyMax;
4884 if (lpmi->fMask & MIM_MENUDATA)
4885 menu->dwMenuData = lpmi->dwMenuData;
4887 if (lpmi->fMask & MIM_STYLE)
4888 menu->dwStyle = lpmi->dwStyle;
4895 /**********************************************************************
4902 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4905 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4907 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4910 if (lpmi->fMask & MIM_BACKGROUND)
4911 lpmi->hbrBack = menu->hbrBack;
4913 if (lpmi->fMask & MIM_HELPID)
4914 lpmi->dwContextHelpID = menu->dwContextHelpID;
4916 if (lpmi->fMask & MIM_MAXHEIGHT)
4917 lpmi->cyMax = menu->cyMax;
4919 if (lpmi->fMask & MIM_MENUDATA)
4920 lpmi->dwMenuData = menu->dwMenuData;
4922 if (lpmi->fMask & MIM_STYLE)
4923 lpmi->dwStyle = menu->dwStyle;
4930 /**********************************************************************
4931 * SetMenuContextHelpId16 (USER.384)
4933 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4935 return SetMenuContextHelpId( hMenu, dwContextHelpID );
4939 /**********************************************************************
4940 * SetMenuContextHelpId (USER32.488)
4942 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4946 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4948 if ((menu = MENU_GetMenu(hMenu)))
4950 menu->dwContextHelpID = dwContextHelpID;
4956 /**********************************************************************
4957 * GetMenuContextHelpId16 (USER.385)
4959 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4961 return GetMenuContextHelpId( hMenu );
4964 /**********************************************************************
4965 * GetMenuContextHelpId (USER32.488)
4967 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4971 TRACE("(0x%04x)\n", hMenu);
4973 if ((menu = MENU_GetMenu(hMenu)))
4975 return menu->dwContextHelpID;
4980 /**********************************************************************
4981 * MenuItemFromPoint (USER32.387)
4983 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4985 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4986 hWnd, hMenu, ptScreen.x, ptScreen.y);
4991 /**********************************************************************
4992 * translate_accelerator
4994 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4995 BYTE fVirt, WORD key, WORD cmd )
4999 if (wParam != key) return FALSE;
5001 if (message == WM_CHAR)
5003 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
5005 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
5011 if(fVirt & FVIRTKEY)
5014 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
5015 wParam, 0xff & HIWORD(lParam));
5016 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
5017 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
5018 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
5019 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
5020 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
5024 if (!(lParam & 0x01000000)) /* no special_key */
5026 if ((fVirt & FALT) && (lParam & 0x20000000))
5027 { /* ^^ ALT pressed */
5028 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
5037 if (message == WM_KEYUP || message == WM_SYSKEYUP)
5039 else if (GetCapture())
5041 else if (!IsWindowEnabled(hWnd))
5045 HMENU hMenu, hSubMenu, hSysMenu;
5046 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
5047 WND* wndPtr = WIN_FindWndPtr(hWnd);
5049 hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU)wndPtr->wIDmenu;
5050 hSysMenu = wndPtr->hSysMenu;
5051 WIN_ReleaseWndPtr(wndPtr);
5053 /* find menu item and ask application to initialize it */
5054 /* 1. in the system menu */
5055 hSubMenu = hSysMenu;
5057 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5059 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
5060 if(hSubMenu != hSysMenu)
5062 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
5063 TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
5064 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
5066 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
5068 else /* 2. in the window's menu */
5072 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
5074 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
5075 if(hSubMenu != hMenu)
5077 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
5078 TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
5079 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
5081 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
5085 if (uSysStat != (UINT)-1)
5087 if (uSysStat & (MF_DISABLED|MF_GRAYED))
5094 if (uStat != (UINT)-1)
5100 if (uStat & (MF_DISABLED|MF_GRAYED))
5111 if( mesg==WM_COMMAND )
5113 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
5114 SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
5116 else if( mesg==WM_SYSCOMMAND )
5118 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
5119 SendMessageA(hWnd, mesg, cmd, 0x00010000L);
5123 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5124 * #0: unknown (please report!)
5125 * #1: for WM_KEYUP,WM_SYSKEYUP
5126 * #2: mouse is captured
5127 * #3: window is disabled
5128 * #4: it's a disabled system menu option
5129 * #5: it's a menu option, but window is iconic
5130 * #6: it's a menu option, but disabled
5132 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
5134 ERR_(accel)(" unknown reason - please report!");
5139 /**********************************************************************
5140 * TranslateAccelerator (USER32.551)(USER32.552)(USER32.553)
5142 INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
5145 LPACCEL16 lpAccelTbl;
5150 WARN_(accel)("msg null; should hang here to be win compatible\n");
5153 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(hAccel)))
5155 WARN_(accel)("invalid accel handle=%x\n", hAccel);
5158 if ((msg->message != WM_KEYDOWN &&
5159 msg->message != WM_KEYUP &&
5160 msg->message != WM_SYSKEYDOWN &&
5161 msg->message != WM_SYSKEYUP &&
5162 msg->message != WM_CHAR)) return 0;
5164 TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5165 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5166 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5171 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5172 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5174 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5175 WARN_(accel)("couldn't translate accelerator key\n");
5180 /**********************************************************************
5181 * TranslateAccelerator16 (USER.178)
5183 INT16 WINAPI TranslateAccelerator16( HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg )
5185 LPACCEL16 lpAccelTbl;
5190 WARN_(accel)("msg null; should hang here to be win compatible\n");
5193 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(hAccel)))
5195 WARN_(accel)("invalid accel handle=%x\n", hAccel);
5198 if ((msg->message != WM_KEYDOWN &&
5199 msg->message != WM_KEYUP &&
5200 msg->message != WM_SYSKEYDOWN &&
5201 msg->message != WM_SYSKEYUP &&
5202 msg->message != WM_CHAR)) return 0;
5204 TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5205 "msg->hwnd=%04x, msg->message=%04x, wParam=%04x, lParam=%lx\n",
5206 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5211 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5212 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd ))
5214 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5215 WARN_(accel)("couldn't translate accelerator key\n");