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.
22 #include "wine/winbase16.h"
23 #include "wine/winuser16.h"
28 #include "nonclient.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(menu)
39 /* internal popup menu window messages */
41 #define MM_SETMENUHANDLE (WM_USER + 0)
42 #define MM_GETMENUHANDLE (WM_USER + 1)
44 /* Menu item structure */
46 /* ----------- MENUITEMINFO Stuff ----------- */
47 UINT fType; /* Item type. */
48 UINT fState; /* Item state. */
49 UINT wID; /* Item id. */
50 HMENU hSubMenu; /* Pop-up menu. */
51 HBITMAP hCheckBit; /* Bitmap when checked. */
52 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
53 LPSTR text; /* Item text or bitmap handle. */
54 DWORD dwItemData; /* Application defined. */
55 DWORD dwTypeData; /* depends on fMask */
56 HBITMAP hbmpItem; /* bitmap in win98 style menus */
57 /* ----------- Wine stuff ----------- */
58 RECT rect; /* Item area (relative to menu window) */
59 UINT xTab; /* X position of text after Tab */
62 /* Popup menu structure */
64 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
65 WORD wMagic; /* Magic number */
66 HQUEUE16 hTaskQ; /* Task queue for this menu */
67 WORD Width; /* Width of the whole menu */
68 WORD Height; /* Height of the whole menu */
69 WORD nItems; /* Number of items in the menu */
70 HWND hWnd; /* Window containing the menu */
71 MENUITEM *items; /* Array of menu items */
72 UINT FocusedItem; /* Currently focused item */
73 HWND hwndOwner; /* window receiving the messages for ownerdraw */
74 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
75 /* ------------ MENUINFO members ------ */
76 DWORD dwStyle; /* Extended mennu style */
77 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
78 HBRUSH hbrBack; /* brush for menu background */
79 DWORD dwContextHelpID;
80 DWORD dwMenuData; /* application defined value */
81 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
82 } POPUPMENU, *LPPOPUPMENU;
84 /* internal flags for menu tracking */
86 #define TF_ENDMENU 0x0001
87 #define TF_SUSPENDPOPUP 0x0002
88 #define TF_SKIPREMOVE 0x0004
93 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
94 HMENU hTopMenu; /* initial menu */
95 HWND hOwnerWnd; /* where notifications are sent */
99 #define MENU_MAGIC 0x554d /* 'MU' */
100 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
105 /* Internal MENU_TrackMenu() flags */
106 #define TPM_INTERNAL 0xF0000000
107 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
108 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
109 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
111 /* popup menu shade thickness */
112 #define POPUP_XSHADE 4
113 #define POPUP_YSHADE 4
115 /* Space between 2 menu bar items */
116 #define MENU_BAR_ITEMS_SPACE 12
118 /* Minimum width of a tab character */
119 #define MENU_TAB_SPACE 8
121 /* Height of a separator item */
122 #define SEPARATOR_HEIGHT 5
124 /* (other menu->FocusedItem values give the position of the focused item) */
125 #define NO_SELECTED_ITEM 0xffff
127 #define MENU_ITEM_TYPE(flags) \
128 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
130 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
131 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
133 #define IS_SYSTEM_MENU(menu) \
134 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
136 #define IS_SYSTEM_POPUP(menu) \
137 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
139 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
140 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
141 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
142 MF_POPUP | MF_SYSMENU | MF_HELP)
143 #define STATE_MASK (~TYPE_MASK)
145 /* Dimension of the menu bitmaps */
146 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
147 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
149 static HBITMAP hStdRadioCheck = 0;
150 static HBITMAP hStdCheck = 0;
151 static HBITMAP hStdMnArrow = 0;
153 /* Minimze/restore/close buttons to be inserted in menubar */
154 static HBITMAP hBmpMinimize = 0;
155 static HBITMAP hBmpMinimizeD = 0;
156 static HBITMAP hBmpMaximize = 0;
157 static HBITMAP hBmpMaximizeD = 0;
158 static HBITMAP hBmpClose = 0;
159 static HBITMAP hBmpCloseD = 0;
162 static HBRUSH hShadeBrush = 0;
163 static HFONT hMenuFont = 0;
164 static HFONT hMenuFontBold = 0;
166 static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
168 /* Use global popup window because there's no way 2 menus can
169 * be tracked at the same time. */
171 static WND* pTopPopupWnd = 0;
172 static UINT uSubPWndLevel = 0;
174 /* Flag set by EndMenu() to force an exit from menu tracking */
175 static BOOL fEndMenu = FALSE;
178 /***********************************************************************
179 * debug_print_menuitem
181 * Print a menuitem in readable form.
184 #define debug_print_menuitem(pre, mp, post) \
185 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
187 #define MENUOUT(text) \
188 DPRINTF("%s%s", (count++ ? "," : ""), (text))
190 #define MENUFLAG(bit,text) \
192 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
195 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
198 TRACE("%s ", prefix);
200 UINT flags = mp->fType;
201 int typ = MENU_ITEM_TYPE(flags);
202 DPRINTF( "{ ID=0x%x", mp->wID);
203 if (flags & MF_POPUP)
204 DPRINTF( ", Sub=0x%x", mp->hSubMenu);
208 if (typ == MFT_STRING)
210 else if (typ == MFT_SEPARATOR)
212 else if (typ == MFT_OWNERDRAW)
214 else if (typ == MFT_BITMAP)
220 MENUFLAG(MF_POPUP, "pop");
221 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
222 MENUFLAG(MFT_MENUBREAK, "brk");
223 MENUFLAG(MFT_RADIOCHECK, "radio");
224 MENUFLAG(MFT_RIGHTORDER, "rorder");
225 MENUFLAG(MF_SYSMENU, "sys");
226 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
229 DPRINTF( "+0x%x", flags);
234 DPRINTF( ", State=");
235 MENUFLAG(MFS_GRAYED, "grey");
236 MENUFLAG(MFS_DEFAULT, "default");
237 MENUFLAG(MFS_DISABLED, "dis");
238 MENUFLAG(MFS_CHECKED, "check");
239 MENUFLAG(MFS_HILITE, "hi");
240 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
241 MENUFLAG(MF_MOUSESELECT, "mouse");
243 DPRINTF( "+0x%x", flags);
246 DPRINTF( ", Chk=0x%x", mp->hCheckBit);
248 DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
250 if (typ == MFT_STRING) {
252 DPRINTF( ", Text=\"%s\"", mp->text);
254 DPRINTF( ", Text=Null");
255 } else if (mp->text == NULL)
258 DPRINTF( ", Text=%p", mp->text);
260 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
266 DPRINTF(" %s\n", postfix);
273 /***********************************************************************
276 * Validate the given menu handle and returns the menu structure pointer.
278 POPUPMENU *MENU_GetMenu(HMENU hMenu)
281 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
282 if (!IS_A_MENU(menu))
284 ERR("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
290 /***********************************************************************
293 * Return the default system menu.
295 static HMENU MENU_CopySysPopup(void)
297 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
300 POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
301 menu->wFlags |= MF_SYSMENU | MF_POPUP;
302 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
306 ERR("Unable to load default system menu\n" );
309 TRACE("returning %x.\n", hMenu );
314 /***********************************************************************
315 * MENU_GetTopPopupWnd()
317 * Return the locked pointer pTopPopupWnd.
319 static WND *MENU_GetTopPopupWnd()
321 return WIN_LockWndPtr(pTopPopupWnd);
323 /***********************************************************************
324 * MENU_ReleaseTopPopupWnd()
326 * Realease the locked pointer pTopPopupWnd.
328 static void MENU_ReleaseTopPopupWnd()
330 WIN_ReleaseWndPtr(pTopPopupWnd);
332 /***********************************************************************
333 * MENU_DestroyTopPopupWnd()
335 * Destroy the locked pointer pTopPopupWnd.
337 static void MENU_DestroyTopPopupWnd()
339 WND *tmpWnd = pTopPopupWnd;
341 WIN_ReleaseWndPtr(tmpWnd);
346 /**********************************************************************
349 * Create a copy of the system menu. System menu in Windows is
350 * a special menu-bar with the single entry - system menu popup.
351 * This popup is presented to the outside world as a "system menu".
352 * However, the real system menu handle is sometimes seen in the
353 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
355 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
359 if ((hMenu = CreateMenu()))
361 POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
362 menu->wFlags = MF_SYSMENU;
365 if (hPopupMenu == (HMENU)(-1))
366 hPopupMenu = MENU_CopySysPopup();
367 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
371 InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
373 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
374 menu->items[0].fState = 0;
375 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
376 menu->wFlags |= MF_SYSMENU;
378 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
381 DestroyMenu( hMenu );
383 ERR("failed to load system menu!\n");
388 /***********************************************************************
391 * Menus initialisation.
396 NONCLIENTMETRICSA ncm;
398 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
403 /* Load menu bitmaps */
404 hStdCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK));
405 hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK));
406 hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
407 /* Load system buttons bitmaps */
408 hBmpMinimize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE));
409 hBmpMinimizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED));
410 hBmpMaximize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE));
411 hBmpMaximizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED));
412 hBmpClose = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE));
413 hBmpCloseD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED));
418 GetObjectA( hStdCheck, sizeof(bm), &bm );
419 check_bitmap_width = bm.bmWidth;
420 check_bitmap_height = bm.bmHeight;
424 /* Assume that radio checks have the same size as regular check. */
431 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
432 arrow_bitmap_width = bm.bmWidth;
433 arrow_bitmap_height = bm.bmHeight;
437 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
440 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
443 DeleteObject( hBitmap );
444 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
447 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
448 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
451 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
454 ncm.lfMenuFont.lfWeight += 300;
455 if ( ncm.lfMenuFont.lfWeight > 1000)
456 ncm.lfMenuFont.lfWeight = 1000;
458 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
464 /***********************************************************************
465 * MENU_InitSysMenuPopup
467 * Grey the appropriate items in System menu.
469 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
473 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
474 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
475 gray = ((style & WS_MAXIMIZE) != 0);
476 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
477 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
478 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
479 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
480 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
481 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
482 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
483 gray = (clsStyle & CS_NOCLOSE) != 0;
485 /* The menu item must keep its state if it's disabled */
487 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
491 /******************************************************************************
493 * UINT MENU_GetStartOfNextColumn(
496 *****************************************************************************/
498 static UINT MENU_GetStartOfNextColumn(
501 POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
502 UINT i = menu->FocusedItem + 1;
505 return NO_SELECTED_ITEM;
507 if( i == NO_SELECTED_ITEM )
510 for( ; i < menu->nItems; ++i ) {
511 if (menu->items[i].fType & MF_MENUBARBREAK)
515 return NO_SELECTED_ITEM;
519 /******************************************************************************
521 * UINT MENU_GetStartOfPrevColumn(
524 *****************************************************************************/
526 static UINT MENU_GetStartOfPrevColumn(
529 POPUPMENU const *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
533 return NO_SELECTED_ITEM;
535 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
536 return NO_SELECTED_ITEM;
538 /* Find the start of the column */
540 for(i = menu->FocusedItem; i != 0 &&
541 !(menu->items[i].fType & MF_MENUBARBREAK);
545 return NO_SELECTED_ITEM;
547 for(--i; i != 0; --i) {
548 if (menu->items[i].fType & MF_MENUBARBREAK)
552 TRACE("ret %d.\n", i );
559 /***********************************************************************
562 * Find a menu item. Return a pointer on the item, and modifies *hmenu
563 * in case the item was in a sub-menu.
565 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
570 if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
571 if (wFlags & MF_BYPOSITION)
573 if (*nPos >= menu->nItems) return NULL;
574 return &menu->items[*nPos];
578 MENUITEM *item = menu->items;
579 for (i = 0; i < menu->nItems; i++, item++)
581 if (item->wID == *nPos)
586 else if (item->fType & MF_POPUP)
588 HMENU hsubmenu = item->hSubMenu;
589 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
601 /***********************************************************************
604 * Find a Sub menu. Return the position of the submenu, and modifies
605 * *hmenu in case it is found in another sub-menu.
606 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
608 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
613 if (((*hmenu)==0xffff) ||
614 (!(menu = MENU_GetMenu(*hmenu))))
615 return NO_SELECTED_ITEM;
617 for (i = 0; i < menu->nItems; i++, item++) {
618 if(!(item->fType & MF_POPUP)) continue;
619 if (item->hSubMenu == hSubTarget) {
623 HMENU hsubmenu = item->hSubMenu;
624 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
625 if (pos != NO_SELECTED_ITEM) {
631 return NO_SELECTED_ITEM;
634 /***********************************************************************
637 static void MENU_FreeItemData( MENUITEM* item )
640 if (IS_STRING_ITEM(item->fType) && item->text)
641 HeapFree( SystemHeap, 0, item->text );
644 /***********************************************************************
645 * MENU_FindItemByCoords
647 * Find the item at the specified coordinates (screen coords). Does
648 * not work for child windows and therefore should not be called for
649 * an arbitrary system menu.
651 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
652 POINT pt, UINT *pos )
658 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
659 pt.x -= wrect.left;pt.y -= wrect.top;
661 for (i = 0; i < menu->nItems; i++, item++)
663 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
664 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
674 /***********************************************************************
677 * Find the menu item selected by a key press.
678 * Return item id, -1 if none, -2 if we should close the menu.
680 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
681 UINT key, BOOL forceMenuChar )
683 TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
685 if (!IsMenu( hmenu ))
687 WND* w = WIN_FindWndPtr(hwndOwner);
688 hmenu = GetSubMenu(w->hSysMenu, 0);
689 WIN_ReleaseWndPtr(w);
694 POPUPMENU *menu = MENU_GetMenu( hmenu );
695 MENUITEM *item = menu->items;
703 for (i = 0; i < menu->nItems; i++, item++)
705 if (item->text && (IS_STRING_ITEM(item->fType)))
707 char *p = item->text - 2;
710 p = strchr (p + 2, '&');
712 while (p != NULL && p [1] == '&');
713 if (p && (toupper(p[1]) == key)) return i;
717 menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
718 MAKEWPARAM( key, menu->wFlags ), hmenu );
719 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
720 if (HIWORD(menuchar) == 1) return (UINT)(-2);
724 /***********************************************************************
727 * Load the bitmap associated with the magic menu item and its style
730 static HBITMAP MENU_LoadMagicItem(UINT id, BOOL hilite, DWORD dwItemData)
733 * Magic menu item id's section
734 * These magic id's are used by windows to insert "standard" mdi
735 * buttons (minimize,restore,close) on menu. Under windows,
736 * these magic id's make sure the right things appear when those
737 * bitmap buttons are pressed/selected/released.
741 { case HBMMENU_SYSTEM:
742 return (dwItemData) ?
743 (HBITMAP)dwItemData :
744 (hilite ? hBmpMinimizeD : hBmpMinimize);
745 case HBMMENU_MBAR_RESTORE:
746 return (hilite ? hBmpMaximizeD: hBmpMaximize);
747 case HBMMENU_MBAR_MINIMIZE:
748 return (hilite ? hBmpMinimizeD : hBmpMinimize);
749 case HBMMENU_MBAR_CLOSE:
750 return (hilite ? hBmpCloseD : hBmpClose);
751 case HBMMENU_CALLBACK:
752 case HBMMENU_MBAR_CLOSE_D:
753 case HBMMENU_MBAR_MINIMIZE_D:
754 case HBMMENU_POPUP_CLOSE:
755 case HBMMENU_POPUP_RESTORE:
756 case HBMMENU_POPUP_MAXIMIZE:
757 case HBMMENU_POPUP_MINIMIZE:
759 FIXME("Magic 0x%08x not implemented\n", id);
765 /***********************************************************************
768 * Calculate the size of the menu item and store it in lpitem->rect.
770 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
771 INT orgX, INT orgY, BOOL menuBar )
775 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
776 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
777 (menuBar ? " (MenuBar)" : ""));
779 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
781 if (lpitem->fType & MF_OWNERDRAW)
784 ** Experimentation under Windows reveals that an owner-drawn
785 ** menu is expected to return the size of the content part of
786 ** the menu item, not including the checkmark nor the submenu
787 ** arrow. Windows adds those values itself and returns the
788 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
790 MEASUREITEMSTRUCT mis;
791 mis.CtlType = ODT_MENU;
793 mis.itemID = lpitem->wID;
794 mis.itemData = (DWORD)lpitem->dwItemData;
797 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
798 lpitem->rect.right += mis.itemWidth;
802 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
805 /* under at least win95 you seem to be given a standard
806 height for the menu and the height value is ignored */
808 if (TWEAK_WineLook == WIN31_LOOK)
809 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
811 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
814 lpitem->rect.bottom += mis.itemHeight;
816 TRACE("id=%04x size=%dx%d\n",
817 lpitem->wID, mis.itemWidth, mis.itemHeight);
818 /* Fall through to get check/arrow width calculation. */
821 if (lpitem->fType & MF_SEPARATOR)
823 lpitem->rect.bottom += SEPARATOR_HEIGHT;
829 lpitem->rect.right += 2 * check_bitmap_width;
830 if (lpitem->fType & MF_POPUP)
831 lpitem->rect.right += arrow_bitmap_width;
834 if (lpitem->fType & MF_OWNERDRAW)
837 if (IS_BITMAP_ITEM(lpitem->fType))
842 /* Check if there is a magic menu item associated with this item */
843 if((LOWORD((int)lpitem->text))<12)
845 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fType & MF_HILITE),
849 resBmp = (HBITMAP)lpitem->text;
851 if (GetObjectA(resBmp, sizeof(bm), &bm ))
853 lpitem->rect.right += bm.bmWidth;
854 lpitem->rect.bottom += bm.bmHeight;
860 /* If we get here, then it must be a text item */
861 if (IS_STRING_ITEM( lpitem->fType ))
864 GetTextExtentPoint32A(hdc, lpitem->text, strlen(lpitem->text), &size);
866 lpitem->rect.right += size.cx;
867 if (TWEAK_WineLook == WIN31_LOOK)
868 lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
870 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
875 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
877 else if ((p = strchr( lpitem->text, '\t' )) != NULL)
879 /* Item contains a tab (only meaningful in popup menus) */
880 GetTextExtentPoint32A(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
881 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
882 lpitem->rect.right += MENU_TAB_SPACE;
886 if (strchr( lpitem->text, '\b' ))
887 lpitem->rect.right += MENU_TAB_SPACE;
888 lpitem->xTab = lpitem->rect.right - check_bitmap_width
889 - arrow_bitmap_width;
892 TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
896 /***********************************************************************
897 * MENU_PopupMenuCalcSize
899 * Calculate the size of a popup menu.
901 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
906 int orgX, orgY, maxX, maxTab, maxTabWidth;
908 lppop->Width = lppop->Height = 0;
909 if (lppop->nItems == 0) return;
912 SelectObject( hdc, hMenuFont);
915 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2 ;
917 while (start < lppop->nItems)
919 lpitem = &lppop->items[start];
921 orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
923 maxTab = maxTabWidth = 0;
925 /* Parse items until column break or end of menu */
926 for (i = start; i < lppop->nItems; i++, lpitem++)
929 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
931 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
933 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
934 maxX = max( maxX, lpitem->rect.right );
935 orgY = lpitem->rect.bottom;
936 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
938 maxTab = max( maxTab, lpitem->xTab );
939 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
943 /* Finish the column (set all items to the largest width found) */
944 maxX = max( maxX, maxTab + maxTabWidth );
945 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
947 lpitem->rect.right = maxX;
948 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
949 lpitem->xTab = maxTab;
952 lppop->Height = max( lppop->Height, orgY );
957 /* space for 3d border */
958 if(TWEAK_WineLook > WIN31_LOOK)
968 /***********************************************************************
969 * MENU_MenuBarCalcSize
971 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
972 * height is off by 1 pixel which causes lengthy window relocations when
973 * active document window is maximized/restored.
975 * Calculate the size of the menu bar.
977 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
978 LPPOPUPMENU lppop, HWND hwndOwner )
981 int start, i, orgX, orgY, maxY, helpPos;
983 if ((lprect == NULL) || (lppop == NULL)) return;
984 if (lppop->nItems == 0) return;
985 TRACE("left=%d top=%d right=%d bottom=%d\n",
986 lprect->left, lprect->top, lprect->right, lprect->bottom);
987 lppop->Width = lprect->right - lprect->left;
992 while (start < lppop->nItems)
994 lpitem = &lppop->items[start];
998 /* Parse items until line break or end of menu */
999 for (i = start; i < lppop->nItems; i++, lpitem++)
1001 if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i;
1003 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1005 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1007 debug_print_menuitem (" item: ", lpitem, "");
1008 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1010 if (lpitem->rect.right > lprect->right)
1012 if (i != start) break;
1013 else lpitem->rect.right = lprect->right;
1015 maxY = max( maxY, lpitem->rect.bottom );
1016 orgX = lpitem->rect.right;
1019 /* Finish the line (set all items to the largest height found) */
1020 while (start < i) lppop->items[start++].rect.bottom = maxY;
1023 lprect->bottom = maxY;
1024 lppop->Height = lprect->bottom - lprect->top;
1026 /* Flush right all magic items and items between the MF_HELP and */
1027 /* the last item (if several lines, only move the last line) */
1028 lpitem = &lppop->items[lppop->nItems-1];
1029 orgY = lpitem->rect.top;
1030 orgX = lprect->right;
1031 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
1033 if ( !IS_BITMAP_ITEM(lpitem->fType) && ((helpPos ==-1) ? TRUE : (helpPos>i) ))
1035 if (lpitem->rect.top != orgY) break; /* Other line */
1036 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1037 lpitem->rect.left += orgX - lpitem->rect.right;
1038 lpitem->rect.right = orgX;
1039 orgX = lpitem->rect.left;
1043 /***********************************************************************
1046 * Draw a single menu item.
1048 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1049 UINT height, BOOL menuBar, UINT odaction )
1053 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1055 if (lpitem->fType & MF_SYSMENU)
1057 if( !IsIconic(hwnd) ) {
1058 if (TWEAK_WineLook > WIN31_LOOK)
1059 NC_DrawSysButton95( hwnd, hdc,
1061 (MF_HILITE | MF_MOUSESELECT) );
1063 NC_DrawSysButton( hwnd, hdc,
1065 (MF_HILITE | MF_MOUSESELECT) );
1071 if (lpitem->fType & MF_OWNERDRAW)
1074 ** Experimentation under Windows reveals that an owner-drawn
1075 ** menu is given the rectangle which includes the space it requested
1076 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1077 ** and a popup-menu arrow. This is the value of lpitem->rect.
1078 ** Windows will leave all drawing to the application except for
1079 ** the popup-menu arrow. Windows always draws that itself, after
1080 ** the menu owner has finished drawing.
1084 dis.CtlType = ODT_MENU;
1086 dis.itemID = lpitem->wID;
1087 dis.itemData = (DWORD)lpitem->dwItemData;
1089 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1090 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED;
1091 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1092 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1093 dis.hwndItem = hmenu;
1095 dis.rcItem = lpitem->rect;
1096 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1097 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
1098 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1099 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1101 SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1102 /* Fall through to draw popup-menu arrow */
1105 TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
1106 lpitem->rect.right,lpitem->rect.bottom);
1108 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1110 rect = lpitem->rect;
1112 if (!(lpitem->fType & MF_OWNERDRAW))
1114 if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)))
1115 if ((menuBar) && (TWEAK_WineLook==WIN98_LOOK))
1116 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1118 FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
1120 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1123 SetBkMode( hdc, TRANSPARENT );
1125 if (!(lpitem->fType & MF_OWNERDRAW))
1127 /* vertical separator */
1128 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1130 if (TWEAK_WineLook > WIN31_LOOK)
1134 rc.bottom = height - 3;
1135 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1139 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1140 MoveTo16( hdc, rect.left, 0 );
1141 LineTo( hdc, rect.left, height );
1145 /* horizontal separator */
1146 if (lpitem->fType & MF_SEPARATOR)
1148 if (TWEAK_WineLook > WIN31_LOOK)
1153 rc.top += SEPARATOR_HEIGHT / 2;
1154 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1158 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1159 MoveTo16( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
1160 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1168 if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)) )
1170 if (lpitem->fState & MF_GRAYED)
1171 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1173 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
1174 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
1178 if (lpitem->fState & MF_GRAYED)
1179 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1181 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1182 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1185 /* helper lines for debugging */
1186 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1187 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1188 MoveTo16( hdc, rect.left, (rect.top + rect.bottom)/2 );
1189 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1194 INT y = rect.top + rect.bottom;
1196 if (!(lpitem->fType & MF_OWNERDRAW))
1198 /* Draw the check mark
1201 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1204 if (lpitem->fState & MF_CHECKED)
1206 HBITMAP bm = lpitem->hCheckBit ? lpitem->hCheckBit :
1207 ((lpitem->fType & MFT_RADIOCHECK) ? hStdRadioCheck : hStdCheck);
1208 HDC hdcMem = CreateCompatibleDC( hdc );
1210 SelectObject( hdcMem, bm );
1211 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1212 check_bitmap_width, check_bitmap_height,
1213 hdcMem, 0, 0, SRCCOPY );
1216 else if (lpitem->hUnCheckBit)
1218 HDC hdcMem = CreateCompatibleDC( hdc );
1220 SelectObject( hdcMem, lpitem->hUnCheckBit );
1221 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1222 check_bitmap_width, check_bitmap_height,
1223 hdcMem, 0, 0, SRCCOPY );
1228 /* Draw the popup-menu arrow */
1229 if (lpitem->fType & MF_POPUP)
1231 HDC hdcMem = CreateCompatibleDC( hdc );
1232 HBITMAP hOrigBitmap;
1234 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1235 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1236 (y - arrow_bitmap_height) / 2,
1237 arrow_bitmap_width, arrow_bitmap_height,
1238 hdcMem, 0, 0, SRCCOPY );
1239 SelectObject( hdcMem, hOrigBitmap );
1243 rect.left += check_bitmap_width;
1244 rect.right -= arrow_bitmap_width;
1247 /* Done for owner-drawn */
1248 if (lpitem->fType & MF_OWNERDRAW)
1251 /* Draw the item text or bitmap */
1252 if (IS_BITMAP_ITEM(lpitem->fType))
1257 HDC hdcMem = CreateCompatibleDC( hdc );
1260 * Check if there is a magic menu item associated with this item
1261 * and load the appropriate bitmap
1263 if((LOWORD((int)lpitem->text)) < 12)
1265 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fState & MF_HILITE),
1266 lpitem->dwItemData);
1269 resBmp = (HBITMAP)lpitem->text;
1274 GetObjectA( resBmp, sizeof(bm), &bm );
1276 SelectObject(hdcMem,resBmp );
1278 /* handle fontsize > bitmap_height */
1279 top = ((rect.bottom-rect.top)>bm.bmHeight) ?
1280 rect.top+(rect.bottom-rect.top-bm.bmHeight)/2 : rect.top;
1282 BitBlt( hdc, rect.left, top, rect.right - rect.left,
1283 rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY );
1290 /* No bitmap - process text if present */
1291 else if (IS_STRING_ITEM(lpitem->fType))
1296 UINT uFormat = (menuBar) ?
1297 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1298 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1300 if ( lpitem->fState & MFS_DEFAULT )
1302 hfontOld = SelectObject( hdc, hMenuFontBold);
1307 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1308 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1309 i = strlen( lpitem->text );
1313 for (i = 0; lpitem->text[i]; i++)
1314 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1318 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1320 if (!(lpitem->fState & MF_HILITE) )
1322 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1323 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1324 DrawTextA( hdc, lpitem->text, i, &rect, uFormat );
1325 --rect.left; --rect.top; --rect.right; --rect.bottom;
1327 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1330 DrawTextA( hdc, lpitem->text, i, &rect, uFormat);
1332 /* paint the shortcut text */
1333 if (lpitem->text[i]) /* There's a tab or flush-right char */
1335 if (lpitem->text[i] == '\t')
1337 rect.left = lpitem->xTab;
1338 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1342 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1345 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1347 if (!(lpitem->fState & MF_HILITE) )
1349 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1350 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1351 DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1352 --rect.left; --rect.top; --rect.right; --rect.bottom;
1354 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1356 DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1360 SelectObject (hdc, hfontOld);
1365 /***********************************************************************
1366 * MENU_DrawPopupMenu
1368 * Paint a popup menu.
1370 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1372 HBRUSH hPrevBrush = 0;
1375 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1377 GetClientRect( hwnd, &rect );
1379 if(TWEAK_WineLook == WIN31_LOOK)
1381 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1382 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1385 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1386 && (SelectObject( hdc, hMenuFont)))
1390 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1392 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1398 /* draw 3-d shade */
1399 if(TWEAK_WineLook == WIN31_LOOK) {
1400 SelectObject( hdc, hShadeBrush );
1401 SetBkMode( hdc, TRANSPARENT );
1402 ropPrev = SetROP2( hdc, R2_MASKPEN );
1404 i = rect.right; /* why SetBrushOrg() doesn't? */
1405 PatBlt( hdc, i & 0xfffffffe,
1406 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1407 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1408 rect.bottom - rect.top, 0x00a000c9 );
1410 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1411 i & 0xfffffffe,rect.right - rect.left,
1412 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1413 SelectObject( hdc, hPrevPen );
1414 SelectObject( hdc, hPrevBrush );
1415 SetROP2( hdc, ropPrev );
1418 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1420 /* draw menu items */
1422 menu = MENU_GetMenu( hmenu );
1423 if (menu && menu->nItems)
1428 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1429 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1430 menu->Height, FALSE, ODA_DRAWENTIRE );
1435 SelectObject( hdc, hPrevBrush );
1440 /***********************************************************************
1443 * Paint a menu bar. Returns the height of the menu bar.
1444 * called from [windows/nonclient.c]
1446 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1453 WND *wndPtr = WIN_FindWndPtr( hwnd );
1455 lppop = MENU_GetMenu ((HMENU)wndPtr->wIDmenu );
1456 if (lppop == NULL || lprect == NULL)
1458 retvalue = GetSystemMetrics(SM_CYMENU);
1462 TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1464 hfontOld = SelectObject( hDC, hMenuFont);
1466 if (lppop->Height == 0)
1467 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1469 lprect->bottom = lprect->top + lppop->Height;
1473 retvalue = lppop->Height;
1477 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1479 if (TWEAK_WineLook == WIN31_LOOK)
1481 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1482 MoveTo16( hDC, lprect->left, lprect->bottom );
1483 LineTo( hDC, lprect->right, lprect->bottom );
1487 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1488 MoveTo16( hDC, lprect->left, lprect->bottom );
1489 LineTo( hDC, lprect->right, lprect->bottom );
1492 if (lppop->nItems == 0)
1494 retvalue = GetSystemMetrics(SM_CYMENU);
1498 for (i = 0; i < lppop->nItems; i++)
1500 MENU_DrawMenuItem( hwnd, (HMENU)wndPtr->wIDmenu, hwnd,
1501 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
1503 retvalue = lppop->Height;
1507 SelectObject (hDC, hfontOld);
1509 WIN_ReleaseWndPtr(wndPtr);
1513 /***********************************************************************
1514 * MENU_PatchResidentPopup
1516 BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
1518 WND *pTPWnd = MENU_GetTopPopupWnd();
1524 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1525 checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTPWnd->hmemTaskQ,
1526 pTPWnd->owner ? pTPWnd->owner->hwndSelf : 0);
1528 switch( checkQueue )
1530 case 0: /* checkWnd is the new popup owner */
1533 pTPWnd->owner = checkWnd;
1534 if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
1535 hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
1539 case 0xFFFF: /* checkWnd is destroyed */
1540 if( pTPWnd->owner == checkWnd )
1541 pTPWnd->owner = NULL;
1542 MENU_ReleaseTopPopupWnd();
1545 default: /* checkQueue is exiting */
1546 if( pTPWnd->hmemTaskQ == checkQueue )
1548 hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
1549 hTask = TASK_GetNextTask( hTask );
1556 TDB* task = (TDB*)GlobalLock16( hTask );
1559 pTPWnd->hInstance = task->hInstance;
1560 pTPWnd->hmemTaskQ = task->hQueue;
1561 MENU_ReleaseTopPopupWnd();
1564 else WARN("failed to patch resident popup.\n");
1567 MENU_ReleaseTopPopupWnd();
1571 /***********************************************************************
1574 * Display a popup menu.
1576 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1577 INT x, INT y, INT xanchor, INT yanchor )
1580 WND *wndOwner = NULL;
1582 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1583 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1585 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1586 if (menu->FocusedItem != NO_SELECTED_ITEM)
1588 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1589 menu->FocusedItem = NO_SELECTED_ITEM;
1592 /* store the owner for DrawItem*/
1593 menu->hwndOwner = hwndOwner;
1595 if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
1599 MENU_PopupMenuCalcSize( menu, hwndOwner );
1601 /* adjust popup menu pos so that it fits within the desktop */
1603 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1604 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1606 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1609 x -= width - xanchor;
1610 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1611 x = GetSystemMetrics(SM_CXSCREEN) - width;
1615 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1618 y -= height + yanchor;
1619 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1620 y = GetSystemMetrics(SM_CYSCREEN) - height;
1624 if( TWEAK_WineLook == WIN31_LOOK )
1626 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1627 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1630 /* NOTE: In Windows, top menu popup is not owned. */
1631 if (!pTopPopupWnd) /* create top level popup menu window */
1633 assert( uSubPWndLevel == 0 );
1635 pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1636 WS_POPUP, x, y, width, height,
1637 hwndOwner, 0, wndOwner->hInstance,
1641 WIN_ReleaseWndPtr(wndOwner);
1644 menu->hWnd = pTopPopupWnd->hwndSelf;
1645 MENU_ReleaseTopPopupWnd();
1650 /* create a new window for the submenu */
1652 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1653 WS_POPUP, x, y, width, height,
1654 hwndOwner, 0, wndOwner->hInstance,
1658 WIN_ReleaseWndPtr(wndOwner);
1662 else /* top level popup menu window already exists */
1664 WND *pTPWnd = MENU_GetTopPopupWnd();
1665 menu->hWnd = pTPWnd->hwndSelf;
1667 MENU_PatchResidentPopup( 0, wndOwner );
1668 SendMessageA( pTPWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);
1670 /* adjust its size */
1672 SetWindowPos( menu->hWnd, 0, x, y, width, height,
1673 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
1674 MENU_ReleaseTopPopupWnd();
1677 uSubPWndLevel++; /* menu level counter */
1679 /* Display the window */
1681 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1682 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1683 UpdateWindow( menu->hWnd );
1684 WIN_ReleaseWndPtr(wndOwner);
1691 /***********************************************************************
1694 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1695 BOOL sendMenuSelect, HMENU topmenu )
1700 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1702 lppop = MENU_GetMenu( hmenu );
1703 if ((!lppop) || (!lppop->nItems)) return;
1705 if (lppop->FocusedItem == wIndex) return;
1706 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1707 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1709 SelectObject( hdc, hMenuFont);
1711 /* Clear previous highlighted item */
1712 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1714 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1715 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1716 lppop->Height, !(lppop->wFlags & MF_POPUP),
1720 /* Highlight new item (if any) */
1721 lppop->FocusedItem = wIndex;
1722 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1724 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1725 lppop->items[wIndex].fState |= MF_HILITE;
1726 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1727 &lppop->items[wIndex], lppop->Height,
1728 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1732 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1733 SendMessageA( hwndOwner, WM_MENUSELECT,
1734 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1735 ip->fType | ip->fState | MF_MOUSESELECT |
1736 (lppop->wFlags & MF_SYSMENU)), hmenu);
1739 else if (sendMenuSelect) {
1742 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1743 POPUPMENU *ptm = (POPUPMENU *) USER_HEAP_LIN_ADDR( topmenu );
1744 MENUITEM *ip = &ptm->items[pos];
1745 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1746 ip->fType | ip->fState | MF_MOUSESELECT |
1747 (ptm->wFlags & MF_SYSMENU)), topmenu);
1751 ReleaseDC( lppop->hWnd, hdc );
1755 /***********************************************************************
1756 * MENU_MoveSelection
1758 * Moves currently selected item according to the offset parameter.
1759 * If there is no selection then it should select the last item if
1760 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1762 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1767 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1769 menu = MENU_GetMenu( hmenu );
1770 if ((!menu) || (!menu->items)) return;
1772 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1774 if( menu->nItems == 1 ) return; else
1775 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1777 if (!(menu->items[i].fType & MF_SEPARATOR))
1779 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1784 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1785 i >= 0 && i < menu->nItems ; i += offset)
1786 if (!(menu->items[i].fType & MF_SEPARATOR))
1788 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1794 /**********************************************************************
1797 * Set an item flags, id and text ptr. Called by InsertMenu() and
1800 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1803 LPSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1805 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1807 if (IS_STRING_ITEM(flags))
1811 flags |= MF_SEPARATOR;
1817 /* Item beginning with a backspace is a help item */
1823 if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1827 else if (IS_BITMAP_ITEM(flags))
1828 item->text = (LPSTR)(HBITMAP)LOWORD(str);
1829 else item->text = NULL;
1831 if (flags & MF_OWNERDRAW)
1832 item->dwItemData = (DWORD)str;
1834 item->dwItemData = 0;
1836 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1837 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1839 if (flags & MF_POPUP)
1841 POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1842 if (menu) menu->wFlags |= MF_POPUP;
1854 if (flags & MF_POPUP)
1855 item->hSubMenu = id;
1857 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1858 flags |= MF_POPUP; /* keep popup */
1860 item->fType = flags & TYPE_MASK;
1861 item->fState = (flags & STATE_MASK) &
1862 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1865 /* Don't call SetRectEmpty here! */
1868 if (prevText) HeapFree( SystemHeap, 0, prevText );
1870 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1875 /**********************************************************************
1878 * Insert a new item into a menu.
1880 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1885 if (!(menu = MENU_GetMenu(hMenu)))
1888 /* Find where to insert new item */
1890 if ((pos==(UINT)-1) || ((flags & MF_BYPOSITION) && (pos == menu->nItems))) {
1891 /* Special case: append to menu */
1892 /* Some programs specify the menu length to do that */
1895 if (!MENU_FindItem( &hMenu, &pos, flags ))
1897 FIXME("item %x not found\n", pos );
1900 if (!(menu = MENU_GetMenu(hMenu)))
1904 /* Create new items array */
1906 newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1909 WARN("allocation failed\n" );
1912 if (menu->nItems > 0)
1914 /* Copy the old array into the new */
1915 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1916 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1917 (menu->nItems-pos)*sizeof(MENUITEM) );
1918 HeapFree( SystemHeap, 0, menu->items );
1920 menu->items = newItems;
1922 memset( &newItems[pos], 0, sizeof(*newItems) );
1923 menu->Height = 0; /* force size recalculate */
1924 return &newItems[pos];
1928 /**********************************************************************
1929 * MENU_ParseResource
1931 * Parse a standard menu resource and add items to the menu.
1932 * Return a pointer to the end of the resource.
1934 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1941 flags = GET_WORD(res);
1942 res += sizeof(WORD);
1943 if (!(flags & MF_POPUP))
1946 res += sizeof(WORD);
1948 if (!IS_STRING_ITEM(flags))
1949 ERR("not a string item %04x\n", flags );
1951 if (!unicode) res += strlen(str) + 1;
1952 else res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1953 if (flags & MF_POPUP)
1955 HMENU hSubMenu = CreatePopupMenu();
1956 if (!hSubMenu) return NULL;
1957 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1959 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1960 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1962 else /* Not a popup */
1964 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1965 else AppendMenuW( hMenu, flags, id,
1966 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1968 } while (!(flags & MF_END));
1973 /**********************************************************************
1974 * MENUEX_ParseResource
1976 * Parse an extended menu resource and add items to the menu.
1977 * Return a pointer to the end of the resource.
1979 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1985 mii.cbSize = sizeof(mii);
1986 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1987 mii.fType = GET_DWORD(res);
1988 res += sizeof(DWORD);
1989 mii.fState = GET_DWORD(res);
1990 res += sizeof(DWORD);
1991 mii.wID = GET_DWORD(res);
1992 res += sizeof(DWORD);
1993 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1994 res += sizeof(WORD);
1995 /* Align the text on a word boundary. */
1996 res += (~((int)res - 1)) & 1;
1997 mii.dwTypeData = (LPWSTR) res;
1998 res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
1999 /* Align the following fields on a dword boundary. */
2000 res += (~((int)res - 1)) & 3;
2002 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2004 LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
2006 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2007 mii.fType, mii.fState, mii.wID, resinfo, newstr);
2008 HeapFree( GetProcessHeap(), 0, newstr );
2011 if (resinfo & 1) { /* Pop-up? */
2012 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2013 res += sizeof(DWORD);
2014 mii.hSubMenu = CreatePopupMenu();
2017 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2018 DestroyMenu(mii.hSubMenu);
2021 mii.fMask |= MIIM_SUBMENU;
2022 mii.fType |= MF_POPUP;
2024 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2025 } while (!(resinfo & MF_END));
2030 /***********************************************************************
2033 * Return the handle of the selected sub-popup menu (if any).
2035 static HMENU MENU_GetSubPopup( HMENU hmenu )
2040 menu = MENU_GetMenu( hmenu );
2042 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2044 item = &menu->items[menu->FocusedItem];
2045 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2046 return item->hSubMenu;
2051 /***********************************************************************
2052 * MENU_HideSubPopups
2054 * Hide the sub-popup menus of this menu.
2056 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2057 BOOL sendMenuSelect )
2059 POPUPMENU *menu = MENU_GetMenu( hmenu );
2061 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2063 if (menu && uSubPWndLevel)
2069 if (menu->FocusedItem != NO_SELECTED_ITEM)
2071 item = &menu->items[menu->FocusedItem];
2072 if (!(item->fType & MF_POPUP) ||
2073 !(item->fState & MF_MOUSESELECT)) return;
2074 item->fState &= ~MF_MOUSESELECT;
2075 hsubmenu = item->hSubMenu;
2078 submenu = MENU_GetMenu( hsubmenu );
2079 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2080 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2082 if (submenu->hWnd == MENU_GetTopPopupWnd()->hwndSelf )
2084 ShowWindow( submenu->hWnd, SW_HIDE );
2089 DestroyWindow( submenu->hWnd );
2092 MENU_ReleaseTopPopupWnd();
2097 /***********************************************************************
2100 * Display the sub-menu of the selected item of this menu.
2101 * Return the handle of the submenu, or hmenu if no submenu to display.
2103 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2104 BOOL selectFirst, UINT wFlags )
2112 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2114 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2116 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
2117 (menu->FocusedItem == NO_SELECTED_ITEM))
2119 WIN_ReleaseWndPtr(wndPtr);
2123 item = &menu->items[menu->FocusedItem];
2124 if (!(item->fType & MF_POPUP) ||
2125 (item->fState & (MF_GRAYED | MF_DISABLED)))
2127 WIN_ReleaseWndPtr(wndPtr);
2131 /* message must be send before using item,
2132 because nearly everything may by changed by the application ! */
2134 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2135 if (!(wFlags & TPM_NONOTIFY))
2136 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2137 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2139 item = &menu->items[menu->FocusedItem];
2142 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2143 if (!(item->fState & MF_HILITE))
2145 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2146 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2148 SelectObject( hdc, hMenuFont);
2150 item->fState |= MF_HILITE;
2151 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2152 ReleaseDC( menu->hWnd, hdc );
2154 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2157 item->fState |= MF_MOUSESELECT;
2159 if (IS_SYSTEM_MENU(menu))
2161 MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, GetClassLongA(wndPtr->hwndSelf, GCL_STYLE));
2163 NC_GetSysPopupPos( wndPtr, &rect );
2164 rect.top = rect.bottom;
2165 rect.right = GetSystemMetrics(SM_CXSIZE);
2166 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2170 if (menu->wFlags & MF_POPUP)
2172 rect.left = wndPtr->rectWindow.left + item->rect.right - GetSystemMetrics(SM_CXBORDER);
2173 rect.top = wndPtr->rectWindow.top + item->rect.top;
2174 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2175 rect.bottom = item->rect.top - item->rect.bottom;
2179 rect.left = wndPtr->rectWindow.left + item->rect.left;
2180 rect.top = wndPtr->rectWindow.top + item->rect.bottom;
2181 rect.right = item->rect.right - item->rect.left;
2182 rect.bottom = item->rect.bottom - item->rect.top;
2186 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2187 rect.left, rect.top, rect.right, rect.bottom );
2189 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2190 WIN_ReleaseWndPtr(wndPtr);
2191 return item->hSubMenu;
2196 /**********************************************************************
2199 BOOL MENU_IsMenuActive(void)
2201 return pTopPopupWnd && (pTopPopupWnd->dwStyle & WS_VISIBLE);
2204 /***********************************************************************
2207 * Walks menu chain trying to find a menu pt maps to.
2209 static HMENU MENU_PtMenu( HMENU hMenu, POINT16 pt )
2211 POPUPMENU *menu = MENU_GetMenu( hMenu );
2212 register UINT ht = menu->FocusedItem;
2214 /* try subpopup first (if any) */
2215 ht = (ht != NO_SELECTED_ITEM &&
2216 (menu->items[ht].fType & MF_POPUP) &&
2217 (menu->items[ht].fState & MF_MOUSESELECT))
2218 ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
2220 if( !ht ) /* check the current window (avoiding WM_HITTEST) */
2222 ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt );
2223 if( menu->wFlags & MF_POPUP )
2224 ht = (ht != (UINT)HTNOWHERE &&
2225 ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
2228 WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
2230 ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu)
2231 : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0;
2232 WIN_ReleaseWndPtr(wndPtr);
2238 /***********************************************************************
2239 * MENU_ExecFocusedItem
2241 * Execute a menu item (for instance when user pressed Enter).
2242 * Return the wID of the executed item. Otherwise, -1 indicating
2243 * that no menu item wase executed;
2244 * Have to receive the flags for the TrackPopupMenu options to avoid
2245 * sending unwanted message.
2248 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2251 POPUPMENU *menu = MENU_GetMenu( hMenu );
2253 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2255 if (!menu || !menu->nItems ||
2256 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2258 item = &menu->items[menu->FocusedItem];
2260 TRACE("%08x %08x %08x\n",
2261 hMenu, item->wID, item->hSubMenu);
2263 if (!(item->fType & MF_POPUP))
2265 if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
2267 /* If TPM_RETURNCMD is set you return the id, but
2268 do not send a message to the owner */
2269 if(!(wFlags & TPM_RETURNCMD))
2271 if( menu->wFlags & MF_SYSMENU )
2272 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2273 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2275 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2281 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2286 /***********************************************************************
2287 * MENU_SwitchTracking
2289 * Helper function for menu navigation routines.
2291 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2293 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2294 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2296 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2298 if( pmt->hTopMenu != hPtMenu &&
2299 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2301 /* both are top level menus (system and menu-bar) */
2302 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2303 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2304 pmt->hTopMenu = hPtMenu;
2306 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2307 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2311 /***********************************************************************
2314 * Return TRUE if we can go on with menu tracking.
2316 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2318 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2323 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2326 if( IS_SYSTEM_MENU(ptmenu) )
2327 item = ptmenu->items;
2329 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2333 if( ptmenu->FocusedItem != id )
2334 MENU_SwitchTracking( pmt, hPtMenu, id );
2336 /* If the popup menu is not already "popped" */
2337 if(!(item->fState & MF_MOUSESELECT ))
2339 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2341 /* In win31, a newly popped menu always remain opened for the next buttonup */
2342 if(TWEAK_WineLook == WIN31_LOOK)
2343 ptmenu->bTimeToHide = FALSE;
2348 /* Else the click was on the menu bar, finish the tracking */
2353 /***********************************************************************
2356 * Return the value of MENU_ExecFocusedItem if
2357 * the selected item was not a popup. Else open the popup.
2358 * A -1 return value indicates that we go on with menu tracking.
2361 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2363 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2368 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2371 if( IS_SYSTEM_MENU(ptmenu) )
2372 item = ptmenu->items;
2374 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2376 if( item && (ptmenu->FocusedItem == id ))
2378 if( !(item->fType & MF_POPUP) )
2379 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2381 /* If we are dealing with the top-level menu and that this */
2382 /* is a click on an already "poppped" item */
2383 /* Stop the menu tracking and close the opened submenus */
2384 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2387 ptmenu->bTimeToHide = TRUE;
2393 /***********************************************************************
2396 * Return TRUE if we can go on with menu tracking.
2398 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2400 UINT id = NO_SELECTED_ITEM;
2401 POPUPMENU *ptmenu = NULL;
2405 ptmenu = MENU_GetMenu( hPtMenu );
2406 if( IS_SYSTEM_MENU(ptmenu) )
2409 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2412 if( id == NO_SELECTED_ITEM )
2414 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2415 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2418 else if( ptmenu->FocusedItem != id )
2420 MENU_SwitchTracking( pmt, hPtMenu, id );
2421 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2427 /***********************************************************************
2430 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2432 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2434 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2436 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2437 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2443 LRESULT l = SendMessageA( pmt->hOwnerWnd, WM_NEXTMENU, vk,
2444 (IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
2446 TRACE("%04x [%04x] -> %04x [%04x]\n",
2447 (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
2451 wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
2453 hNewWnd = pmt->hOwnerWnd;
2454 if( IS_SYSTEM_MENU(menu) )
2456 /* switch to the menu bar */
2458 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
2460 WIN_ReleaseWndPtr(wndPtr);
2464 hNewMenu = wndPtr->wIDmenu;
2467 menu = MENU_GetMenu( hNewMenu );
2468 id = menu->nItems - 1;
2471 else if( wndPtr->dwStyle & WS_SYSMENU )
2473 /* switch to the system menu */
2474 hNewMenu = wndPtr->hSysMenu;
2478 WIN_ReleaseWndPtr(wndPtr);
2481 WIN_ReleaseWndPtr(wndPtr);
2483 else /* application returned a new menu to switch to */
2485 hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
2487 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2489 wndPtr = WIN_FindWndPtr(hNewWnd);
2491 if( wndPtr->dwStyle & WS_SYSMENU &&
2492 GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
2494 /* get the real system menu */
2495 hNewMenu = wndPtr->hSysMenu;
2497 else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
2499 /* FIXME: Not sure what to do here, perhaps,
2500 * try to track hNewMenu as a popup? */
2502 TRACE(" -- got confused.\n");
2503 WIN_ReleaseWndPtr(wndPtr);
2506 WIN_ReleaseWndPtr(wndPtr);
2511 if( hNewMenu != pmt->hTopMenu )
2513 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2515 if( pmt->hCurrentMenu != pmt->hTopMenu )
2516 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2519 if( hNewWnd != pmt->hOwnerWnd )
2522 pmt->hOwnerWnd = hNewWnd;
2523 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2526 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2527 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2534 /***********************************************************************
2537 * The idea is not to show the popup if the next input message is
2538 * going to hide it anyway.
2540 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2544 msg.hwnd = pmt->hOwnerWnd;
2546 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2547 pmt->trackFlags |= TF_SKIPREMOVE;
2552 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2553 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2555 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2556 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2557 if( msg.message == WM_KEYDOWN &&
2558 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2560 pmt->trackFlags |= TF_SUSPENDPOPUP;
2567 /* failures go through this */
2568 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2572 /***********************************************************************
2575 * Handle a VK_LEFT key event in a menu.
2577 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2580 HMENU hmenutmp, hmenuprev;
2583 hmenuprev = hmenutmp = pmt->hTopMenu;
2584 menu = MENU_GetMenu( hmenutmp );
2586 /* Try to move 1 column left (if possible) */
2587 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2588 NO_SELECTED_ITEM ) {
2590 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2595 /* close topmost popup */
2596 while (hmenutmp != pmt->hCurrentMenu)
2598 hmenuprev = hmenutmp;
2599 hmenutmp = MENU_GetSubPopup( hmenuprev );
2602 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2603 pmt->hCurrentMenu = hmenuprev;
2605 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2607 /* move menu bar selection if no more popups are left */
2609 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2610 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2612 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2614 /* A sublevel menu was displayed - display the next one
2615 * unless there is another displacement coming up */
2617 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2618 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2619 pmt->hTopMenu, TRUE, wFlags);
2625 /***********************************************************************
2628 * Handle a VK_RIGHT key event in a menu.
2630 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2633 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2636 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2638 (MENU_GetMenu(pmt->hCurrentMenu))->
2640 pmt->hTopMenu, menu->items[0].text );
2642 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2644 /* If already displaying a popup, try to display sub-popup */
2646 hmenutmp = pmt->hCurrentMenu;
2647 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2649 /* if subpopup was displayed then we are done */
2650 if (hmenutmp != pmt->hCurrentMenu) return;
2653 /* Check to see if there's another column */
2654 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2655 NO_SELECTED_ITEM ) {
2656 TRACE("Going to %d.\n", nextcol );
2657 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2662 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2664 if( pmt->hCurrentMenu != pmt->hTopMenu )
2666 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2667 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2668 } else hmenutmp = 0;
2670 /* try to move to the next item */
2671 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2672 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2674 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2675 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2676 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2677 pmt->hTopMenu, TRUE, wFlags);
2681 /***********************************************************************
2684 * Menu tracking code.
2686 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2687 HWND hwnd, const RECT *lprect )
2692 INT executedMenuId = -1;
2694 BOOL enterIdleSent = FALSE;
2697 mt.hCurrentMenu = hmenu;
2698 mt.hTopMenu = hmenu;
2699 mt.hOwnerWnd = hwnd;
2703 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2704 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2705 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2708 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2710 if (wFlags & TPM_BUTTONDOWN)
2712 /* Get the result in order to start the tracking or not */
2713 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2714 fEndMenu = !fRemove;
2717 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2721 menu = MENU_GetMenu( mt.hCurrentMenu );
2722 msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2724 /* we have to keep the message in the queue until it's
2725 * clear that menu loop is not over yet. */
2727 if (!MSG_InternalGetMessage( QMSG_WIN32A, &msg, msg.hwnd, mt.hOwnerWnd,
2728 MSGF_MENU, PM_NOREMOVE, !enterIdleSent, &enterIdleSent )) break;
2730 TranslateMessage( &msg );
2733 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2734 enterIdleSent=FALSE;
2737 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2739 /* Find a menu for this mouse event */
2741 CONV_POINT32TO16( &msg.pt, &pt16 );
2742 hmenu = MENU_PtMenu( mt.hTopMenu, pt16 );
2746 /* no WM_NC... messages in captured state */
2748 case WM_RBUTTONDBLCLK:
2749 case WM_RBUTTONDOWN:
2750 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2752 case WM_LBUTTONDBLCLK:
2753 case WM_LBUTTONDOWN:
2754 /* If the message belongs to the menu, removes it from the queue */
2755 /* Else, end menu tracking */
2756 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2757 fEndMenu = !fRemove;
2761 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2764 /* Check if a menu was selected by the mouse */
2767 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2769 /* End the loop if executedMenuId is an item ID */
2770 /* or if the job was done (executedMenuId = 0). */
2771 fEndMenu = fRemove = (executedMenuId != -1);
2773 /* No menu was selected by the mouse */
2774 /* if the function was called by TrackPopupMenu, continue
2775 with the menu tracking. If not, stop it */
2777 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2782 /* In win95 winelook, the selected menu item must be changed every time the
2783 mouse moves. In Win31 winelook, the mouse button has to be held down */
2785 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2786 ( (msg.wParam & MK_LBUTTON) ||
2787 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2789 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2791 } /* switch(msg.message) - mouse */
2793 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2795 fRemove = TRUE; /* Keyboard messages are always removed */
2803 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2804 NO_SELECTED_ITEM, FALSE, 0 );
2807 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2808 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2811 case VK_DOWN: /* If on menu bar, pull-down the menu */
2813 menu = MENU_GetMenu( mt.hCurrentMenu );
2814 if (!(menu->wFlags & MF_POPUP))
2815 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2816 else /* otherwise try to move selection */
2817 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2821 MENU_KeyLeft( &mt, wFlags );
2825 MENU_KeyRight( &mt, wFlags );
2835 hi.cbSize = sizeof(HELPINFO);
2836 hi.iContextType = HELPINFO_MENUITEM;
2837 if (menu->FocusedItem == NO_SELECTED_ITEM)
2840 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2841 hi.hItemHandle = hmenu;
2842 hi.dwContextId = menu->dwContextHelpID;
2843 hi.MousePos = msg.pt;
2844 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2851 break; /* WM_KEYDOWN */
2861 break; /* WM_SYSKEYDOWN */
2867 if (msg.wParam == '\r' || msg.wParam == ' ')
2869 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2870 fEndMenu = (executedMenuId != -1);
2875 /* Hack to avoid control chars. */
2876 /* We will find a better way real soon... */
2877 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2879 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
2880 LOWORD(msg.wParam), FALSE );
2881 if (pos == (UINT)-2) fEndMenu = TRUE;
2882 else if (pos == (UINT)-1) MessageBeep(0);
2885 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2887 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2888 fEndMenu = (executedMenuId != -1);
2892 } /* switch(msg.message) - kbd */
2896 DispatchMessageA( &msg );
2899 if (!fEndMenu) fRemove = TRUE;
2901 /* finally remove message from the queue */
2903 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2904 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2905 else mt.trackFlags &= ~TF_SKIPREMOVE;
2910 /* If dropdown is still painted and the close box is clicked on
2911 then the menu will be destroyed as part of the DispatchMessage above.
2912 This will then invalidate the menu handle in mt.hTopMenu. We should
2913 check for this first. */
2914 if( IsMenu( mt.hTopMenu ) )
2916 menu = MENU_GetMenu( mt.hTopMenu );
2918 if( IsWindow( mt.hOwnerWnd ) )
2920 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2922 if (menu && menu->wFlags & MF_POPUP)
2924 ShowWindow( menu->hWnd, SW_HIDE );
2927 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2928 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2931 /* Reset the variable for hiding menu */
2932 if( menu ) menu->bTimeToHide = FALSE;
2935 /* The return value is only used by TrackPopupMenu */
2936 return ((executedMenuId != -1) ? executedMenuId : 0);
2939 /***********************************************************************
2942 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
2944 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
2948 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2949 if (!(wFlags & TPM_NONOTIFY))
2950 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2952 SendMessageA( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
2954 if (!(wFlags & TPM_NONOTIFY))
2955 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
2959 /***********************************************************************
2962 static BOOL MENU_ExitTracking(HWND hWnd)
2964 TRACE("hwnd=0x%04x\n", hWnd);
2966 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2971 /***********************************************************************
2972 * MENU_TrackMouseMenuBar
2974 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2976 void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt )
2978 HWND hWnd = wndPtr->hwndSelf;
2979 HMENU hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
2980 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2982 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr, ht, pt.x, pt.y);
2986 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2987 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
2988 MENU_ExitTracking(hWnd);
2993 /***********************************************************************
2994 * MENU_TrackKbdMenuBar
2996 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2998 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
3000 UINT uItem = NO_SELECTED_ITEM;
3002 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3004 /* find window that has a menu */
3006 while( wndPtr->dwStyle & WS_CHILD)
3007 if( !(wndPtr = wndPtr->parent) ) return;
3009 /* check if we have to track a system menu */
3011 if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) ||
3012 !wndPtr->wIDmenu || vkey == VK_SPACE )
3014 if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
3015 hTrackMenu = wndPtr->hSysMenu;
3017 wParam |= HTSYSMENU; /* prevent item lookup */
3020 hTrackMenu = wndPtr->wIDmenu;
3022 if (IsMenu( hTrackMenu ))
3024 MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu, FALSE, wFlags );
3026 if( vkey && vkey != VK_SPACE )
3028 uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu,
3029 vkey, (wParam & HTSYSMENU) );
3030 if( uItem >= (UINT)(-2) )
3032 if( uItem == (UINT)(-1) ) MessageBeep(0);
3039 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE, 0 );
3041 if( uItem == NO_SELECTED_ITEM )
3042 MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
3044 PostMessageA( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
3046 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, wndPtr->hwndSelf, NULL );
3049 MENU_ExitTracking (wndPtr->hwndSelf);
3054 /**********************************************************************
3055 * TrackPopupMenu16 (USER.416)
3057 BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
3058 INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
3062 CONV_RECT16TO32( lpRect, &r );
3063 return TrackPopupMenu( hMenu, wFlags, x, y, nReserved, hWnd,
3064 lpRect ? &r : NULL );
3068 /**********************************************************************
3069 * TrackPopupMenu (USER32.549)
3071 * Like the win32 API, the function return the command ID only if the
3072 * flag TPM_RETURNCMD is on.
3075 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3076 INT nReserved, HWND hWnd, const RECT *lpRect )
3080 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3082 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3083 if (!(wFlags & TPM_NONOTIFY))
3084 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3086 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3087 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3088 MENU_ExitTracking(hWnd);
3090 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3096 /**********************************************************************
3097 * TrackPopupMenuEx (USER32.550)
3099 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3100 HWND hWnd, LPTPMPARAMS lpTpm )
3102 FIXME("not fully implemented\n" );
3103 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3104 lpTpm ? &lpTpm->rcExclude : NULL );
3107 /***********************************************************************
3110 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3112 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
3115 WND* wndPtr = WIN_FindWndPtr(hwnd);
3118 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3119 hwnd, message, wParam, lParam);
3125 CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
3126 SetWindowLongA( hwnd, 0, (LONG)cs->lpCreateParams );
3131 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3132 retvalue = MA_NOACTIVATE;
3138 BeginPaint( hwnd, &ps );
3139 MENU_DrawPopupMenu( hwnd, ps.hdc,
3140 (HMENU)GetWindowLongA( hwnd, 0 ) );
3141 EndPaint( hwnd, &ps );
3151 /* zero out global pointer in case resident popup window
3152 * was somehow destroyed. */
3154 if(MENU_GetTopPopupWnd() )
3156 if( hwnd == pTopPopupWnd->hwndSelf )
3158 ERR("resident popup destroyed!\n");
3160 MENU_DestroyTopPopupWnd();
3165 MENU_ReleaseTopPopupWnd();
3173 if( !(*(HMENU*)wndPtr->wExtra) )
3174 ERR("no menu to display\n");
3177 *(HMENU*)wndPtr->wExtra = 0;
3180 case MM_SETMENUHANDLE:
3182 *(HMENU*)wndPtr->wExtra = (HMENU)wParam;
3185 case MM_GETMENUHANDLE:
3187 retvalue = *(HMENU*)wndPtr->wExtra;
3191 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
3196 WIN_ReleaseWndPtr(wndPtr);
3201 /***********************************************************************
3202 * MENU_GetMenuBarHeight
3204 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3206 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3207 INT orgX, INT orgY )
3215 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3216 hwnd, menubarWidth, orgX, orgY );
3218 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
3221 if (!(lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu)))
3223 WIN_ReleaseWndPtr(wndPtr);
3227 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3228 SelectObject( hdc, hMenuFont);
3229 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3230 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3231 ReleaseDC( hwnd, hdc );
3232 retvalue = lppop->Height;
3233 WIN_ReleaseWndPtr(wndPtr);
3238 /*******************************************************************
3239 * ChangeMenu16 (USER.153)
3241 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3242 UINT16 id, UINT16 flags )
3244 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3245 hMenu, pos, (DWORD)data, id, flags );
3246 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3249 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3250 /* for MF_DELETE. We should check the parameters for all others */
3251 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3253 if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3254 if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3256 if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
3257 flags & MF_BYPOSITION ? pos : id,
3258 flags & ~MF_REMOVE );
3259 /* Default: MF_INSERT */
3260 return InsertMenu16( hMenu, pos, flags, id, data );
3264 /*******************************************************************
3265 * ChangeMenuA (USER32.23)
3267 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3268 UINT id, UINT flags )
3270 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3271 hMenu, pos, (DWORD)data, id, flags );
3272 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3274 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3275 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3277 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3278 flags & MF_BYPOSITION ? pos : id,
3279 flags & ~MF_REMOVE );
3280 /* Default: MF_INSERT */
3281 return InsertMenuA( hMenu, pos, flags, id, data );
3285 /*******************************************************************
3286 * ChangeMenuW (USER32.24)
3288 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3289 UINT id, UINT flags )
3291 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3292 hMenu, pos, (DWORD)data, id, flags );
3293 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3295 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3296 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3298 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3299 flags & MF_BYPOSITION ? pos : id,
3300 flags & ~MF_REMOVE );
3301 /* Default: MF_INSERT */
3302 return InsertMenuW( hMenu, pos, flags, id, data );
3306 /*******************************************************************
3307 * CheckMenuItem16 (USER.154)
3309 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
3311 return (BOOL16)CheckMenuItem( hMenu, id, flags );
3315 /*******************************************************************
3316 * CheckMenuItem (USER32.46)
3318 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3323 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3324 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3325 ret = item->fState & MF_CHECKED;
3326 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3327 else item->fState &= ~MF_CHECKED;
3332 /**********************************************************************
3333 * EnableMenuItem16 (USER.155)
3335 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3337 return EnableMenuItem( hMenu, wItemID, wFlags );
3341 /**********************************************************************
3342 * EnableMenuItem (USER32.170)
3344 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3350 TRACE("(%04x, %04X, %04X) !\n",
3351 hMenu, wItemID, wFlags);
3353 /* Get the Popupmenu to access the owner menu */
3354 if (!(menu = MENU_GetMenu(hMenu)))
3357 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3360 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3361 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3363 /* In win95 if the close item in the system menu change update the close button */
3364 if (TWEAK_WineLook == WIN95_LOOK)
3365 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3367 if (menu->hSysMenuOwner != 0)
3369 POPUPMENU* parentMenu;
3371 /* Get the parent menu to access*/
3372 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3375 /* Refresh the frame to reflect the change*/
3376 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3377 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3385 /*******************************************************************
3386 * GetMenuString16 (USER.161)
3388 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3389 LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
3391 return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
3395 /*******************************************************************
3396 * GetMenuStringA (USER32.268)
3398 INT WINAPI GetMenuStringA(
3399 HMENU hMenu, /* [in] menuhandle */
3400 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3401 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3402 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3403 UINT wFlags /* [in] MF_ flags */
3407 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3408 hMenu, wItemID, str, nMaxSiz, wFlags );
3409 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3410 if (!IS_STRING_ITEM(item->fType)) return 0;
3411 if (!str || !nMaxSiz) return strlen(item->text);
3413 lstrcpynA( str, item->text, nMaxSiz );
3414 TRACE("returning '%s'\n", str );
3419 /*******************************************************************
3420 * GetMenuStringW (USER32.269)
3422 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3423 LPWSTR str, INT nMaxSiz, UINT wFlags )
3427 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3428 hMenu, wItemID, str, nMaxSiz, wFlags );
3429 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3430 if (!IS_STRING_ITEM(item->fType)) return 0;
3431 if (!str || !nMaxSiz) return strlen(item->text);
3433 lstrcpynAtoW( str, item->text, nMaxSiz );
3434 return lstrlenW(str);
3438 /**********************************************************************
3439 * HiliteMenuItem16 (USER.162)
3441 BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
3444 return HiliteMenuItem( hWnd, hMenu, wItemID, wHilite );
3448 /**********************************************************************
3449 * HiliteMenuItem (USER32.318)
3451 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3455 TRACE("(%04x, %04x, %04x, %04x);\n",
3456 hWnd, hMenu, wItemID, wHilite);
3457 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3458 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3459 if (menu->FocusedItem == wItemID) return TRUE;
3460 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3461 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3466 /**********************************************************************
3467 * GetMenuState16 (USER.250)
3469 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3471 return GetMenuState( hMenu, wItemID, wFlags );
3475 /**********************************************************************
3476 * GetMenuState (USER32.267)
3478 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3481 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3482 hMenu, wItemID, wFlags);
3483 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3484 debug_print_menuitem (" item: ", item, "");
3485 if (item->fType & MF_POPUP)
3487 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3488 if (!menu) return -1;
3489 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3493 /* We used to (from way back then) mask the result to 0xff. */
3494 /* I don't know why and it seems wrong as the documented */
3495 /* return flag MF_SEPARATOR is outside that mask. */
3496 return (item->fType | item->fState);
3501 /**********************************************************************
3502 * GetMenuItemCount16 (USER.263)
3504 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3506 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3507 if (!menu) return -1;
3508 TRACE("(%04x) returning %d\n",
3509 hMenu, menu->nItems );
3510 return menu->nItems;
3514 /**********************************************************************
3515 * GetMenuItemCount (USER32.262)
3517 INT WINAPI GetMenuItemCount( HMENU hMenu )
3519 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3520 if (!menu) return -1;
3521 TRACE("(%04x) returning %d\n",
3522 hMenu, menu->nItems );
3523 return menu->nItems;
3526 /**********************************************************************
3527 * GetMenuItemID16 (USER.264)
3529 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3531 return (UINT16) GetMenuItemID (hMenu, nPos);
3534 /**********************************************************************
3535 * GetMenuItemID (USER32.263)
3537 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3541 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3542 if (lpmi->fType & MF_POPUP) return -1;
3547 /*******************************************************************
3548 * InsertMenu16 (USER.410)
3550 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3551 UINT16 id, SEGPTR data )
3553 UINT pos32 = (UINT)pos;
3554 if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3555 if (IS_STRING_ITEM(flags) && data)
3556 return InsertMenuA( hMenu, pos32, flags, id,
3557 (LPSTR)PTR_SEG_TO_LIN(data) );
3558 return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3562 /*******************************************************************
3563 * InsertMenuA (USER32.322)
3565 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3566 UINT id, LPCSTR str )
3570 if (IS_STRING_ITEM(flags) && str)
3571 TRACE("hMenu %04x, pos %d, flags %08x, "
3572 "id %04x, str '%s'\n",
3573 hMenu, pos, flags, id, str );
3574 else TRACE("hMenu %04x, pos %d, flags %08x, "
3575 "id %04x, str %08lx (not a string)\n",
3576 hMenu, pos, flags, id, (DWORD)str );
3578 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3580 if (!(MENU_SetItemData( item, flags, id, str )))
3582 RemoveMenu( hMenu, pos, flags );
3586 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3587 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3589 item->hCheckBit = item->hUnCheckBit = 0;
3594 /*******************************************************************
3595 * InsertMenuW (USER32.325)
3597 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3598 UINT id, LPCWSTR str )
3602 if (IS_STRING_ITEM(flags) && str)
3604 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3605 ret = InsertMenuA( hMenu, pos, flags, id, newstr );
3606 HeapFree( GetProcessHeap(), 0, newstr );
3609 else return InsertMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3613 /*******************************************************************
3614 * AppendMenu16 (USER.411)
3616 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3618 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3622 /*******************************************************************
3623 * AppendMenuA (USER32.5)
3625 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3626 UINT id, LPCSTR data )
3628 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3632 /*******************************************************************
3633 * AppendMenuW (USER32.6)
3635 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3636 UINT id, LPCWSTR data )
3638 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3642 /**********************************************************************
3643 * RemoveMenu16 (USER.412)
3645 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3647 return RemoveMenu( hMenu, nPos, wFlags );
3651 /**********************************************************************
3652 * RemoveMenu (USER32.441)
3654 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3659 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3660 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3661 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3665 MENU_FreeItemData( item );
3667 if (--menu->nItems == 0)
3669 HeapFree( SystemHeap, 0, menu->items );
3674 while(nPos < menu->nItems)
3680 menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
3681 menu->nItems * sizeof(MENUITEM) );
3687 /**********************************************************************
3688 * DeleteMenu16 (USER.413)
3690 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3692 return DeleteMenu( hMenu, nPos, wFlags );
3696 /**********************************************************************
3697 * DeleteMenu (USER32.129)
3699 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3701 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3702 if (!item) return FALSE;
3703 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3704 /* nPos is now the position of the item */
3705 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3710 /*******************************************************************
3711 * ModifyMenu16 (USER.414)
3713 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3714 UINT16 id, SEGPTR data )
3716 if (IS_STRING_ITEM(flags))
3717 return ModifyMenuA( hMenu, pos, flags, id,
3718 (LPSTR)PTR_SEG_TO_LIN(data) );
3719 return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3723 /*******************************************************************
3724 * ModifyMenuA (USER32.397)
3726 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3727 UINT id, LPCSTR str )
3731 if (IS_STRING_ITEM(flags))
3733 TRACE("%04x %d %04x %04x '%s'\n",
3734 hMenu, pos, flags, id, str ? str : "#NULL#" );
3735 if (!str) return FALSE;
3739 TRACE("%04x %d %04x %04x %08lx\n",
3740 hMenu, pos, flags, id, (DWORD)str );
3743 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3744 return MENU_SetItemData( item, flags, id, str );
3748 /*******************************************************************
3749 * ModifyMenuW (USER32.398)
3751 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3752 UINT id, LPCWSTR str )
3756 if (IS_STRING_ITEM(flags) && str)
3758 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3759 ret = ModifyMenuA( hMenu, pos, flags, id, newstr );
3760 HeapFree( GetProcessHeap(), 0, newstr );
3763 else return ModifyMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3767 /**********************************************************************
3768 * CreatePopupMenu16 (USER.415)
3770 HMENU16 WINAPI CreatePopupMenu16(void)
3772 return CreatePopupMenu();
3776 /**********************************************************************
3777 * CreatePopupMenu (USER32.82)
3779 HMENU WINAPI CreatePopupMenu(void)
3784 if (!(hmenu = CreateMenu())) return 0;
3785 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
3786 menu->wFlags |= MF_POPUP;
3787 menu->bTimeToHide = FALSE;
3792 /**********************************************************************
3793 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3795 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3797 return MAKELONG( check_bitmap_width, check_bitmap_height );
3801 /**********************************************************************
3802 * SetMenuItemBitmaps16 (USER.418)
3804 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3805 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3807 return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3811 /**********************************************************************
3812 * SetMenuItemBitmaps (USER32.490)
3814 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3815 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3818 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3819 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3820 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3822 if (!hNewCheck && !hNewUnCheck)
3824 item->fState &= ~MF_USECHECKBITMAPS;
3826 else /* Install new bitmaps */
3828 item->hCheckBit = hNewCheck;
3829 item->hUnCheckBit = hNewUnCheck;
3830 item->fState |= MF_USECHECKBITMAPS;
3836 /**********************************************************************
3837 * CreateMenu16 (USER.151)
3839 HMENU16 WINAPI CreateMenu16(void)
3841 return CreateMenu();
3845 /**********************************************************************
3846 * CreateMenu (USER32.81)
3848 HMENU WINAPI CreateMenu(void)
3852 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3853 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3855 ZeroMemory(menu, sizeof(POPUPMENU));
3856 menu->wMagic = MENU_MAGIC;
3857 menu->FocusedItem = NO_SELECTED_ITEM;
3858 menu->bTimeToHide = FALSE;
3860 TRACE("return %04x\n", hMenu );
3866 /**********************************************************************
3867 * DestroyMenu16 (USER.152)
3869 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3871 return DestroyMenu( hMenu );
3875 /**********************************************************************
3876 * DestroyMenu (USER32.134)
3878 BOOL WINAPI DestroyMenu( HMENU hMenu )
3880 TRACE("(%04x)\n", hMenu);
3882 /* Silently ignore attempts to destroy default system popup */
3884 if (hMenu && hMenu != MENU_DefSysPopup)
3886 LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3887 WND *pTPWnd = MENU_GetTopPopupWnd();
3889 if( pTPWnd && (hMenu == *(HMENU*)pTPWnd->wExtra) )
3890 *(UINT*)pTPWnd->wExtra = 0;
3892 if (!IS_A_MENU(lppop)) lppop = NULL;
3895 lppop->wMagic = 0; /* Mark it as destroyed */
3897 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
3898 (!pTPWnd || (lppop->hWnd != pTPWnd->hwndSelf)))
3899 DestroyWindow( lppop->hWnd );
3901 if (lppop->items) /* recursively destroy submenus */
3904 MENUITEM *item = lppop->items;
3905 for (i = lppop->nItems; i > 0; i--, item++)
3907 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3908 MENU_FreeItemData( item );
3910 HeapFree( SystemHeap, 0, lppop->items );
3912 USER_HEAP_FREE( hMenu );
3913 MENU_ReleaseTopPopupWnd();
3917 MENU_ReleaseTopPopupWnd();
3921 return (hMenu != MENU_DefSysPopup);
3925 /**********************************************************************
3926 * GetSystemMenu16 (USER.156)
3928 HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
3930 return GetSystemMenu( hWnd, bRevert );
3934 /**********************************************************************
3935 * GetSystemMenu (USER32.291)
3937 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3939 WND *wndPtr = WIN_FindWndPtr( hWnd );
3944 if( wndPtr->hSysMenu )
3948 DestroyMenu(wndPtr->hSysMenu);
3949 wndPtr->hSysMenu = 0;
3953 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3956 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3957 menu->items[0].hSubMenu = MENU_CopySysPopup();
3961 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3962 wndPtr->hSysMenu, hWnd);
3963 wndPtr->hSysMenu = 0;
3968 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3969 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3971 if( wndPtr->hSysMenu )
3974 retvalue = GetSubMenu16(wndPtr->hSysMenu, 0);
3976 /* Store the dummy sysmenu handle to facilitate the refresh */
3977 /* of the close button if the SC_CLOSE item change */
3978 menu = MENU_GetMenu(retvalue);
3980 menu->hSysMenuOwner = wndPtr->hSysMenu;
3982 WIN_ReleaseWndPtr(wndPtr);
3988 /*******************************************************************
3989 * SetSystemMenu16 (USER.280)
3991 BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
3993 return SetSystemMenu( hwnd, hMenu );
3997 /*******************************************************************
3998 * SetSystemMenu (USER32.508)
4000 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
4002 WND *wndPtr = WIN_FindWndPtr(hwnd);
4006 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
4007 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
4008 WIN_ReleaseWndPtr(wndPtr);
4015 /**********************************************************************
4016 * GetMenu16 (USER.157)
4018 HMENU16 WINAPI GetMenu16( HWND16 hWnd )
4020 return (HMENU16)GetMenu(hWnd);
4024 /**********************************************************************
4025 * GetMenu (USER32.257)
4027 HMENU WINAPI GetMenu( HWND hWnd )
4030 WND * wndPtr = WIN_FindWndPtr(hWnd);
4031 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4033 retvalue = (HMENU)wndPtr->wIDmenu;
4038 WIN_ReleaseWndPtr(wndPtr);
4043 /**********************************************************************
4044 * SetMenu16 (USER.158)
4046 BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
4048 return SetMenu( hWnd, hMenu );
4052 /**********************************************************************
4053 * SetMenu (USER32.487)
4055 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4057 WND * wndPtr = WIN_FindWndPtr(hWnd);
4059 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4061 if (hMenu && !IsMenu(hMenu))
4063 WARN("hMenu is not a menu handle\n");
4068 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4070 if (GetCapture() == hWnd) ReleaseCapture();
4072 wndPtr->wIDmenu = (UINT)hMenu;
4077 if (!(lpmenu = MENU_GetMenu(hMenu)))
4079 WIN_ReleaseWndPtr(wndPtr);
4082 lpmenu->hWnd = hWnd;
4083 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
4084 lpmenu->Height = 0; /* Make sure we recalculate the size */
4086 if (IsWindowVisible(hWnd))
4087 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4088 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4089 WIN_ReleaseWndPtr(wndPtr);
4092 WIN_ReleaseWndPtr(wndPtr);
4098 /**********************************************************************
4099 * GetSubMenu16 (USER.159)
4101 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
4103 return GetSubMenu( hMenu, nPos );
4107 /**********************************************************************
4108 * GetSubMenu (USER32.288)
4110 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4114 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4115 if (!(lpmi->fType & MF_POPUP)) return 0;
4116 return lpmi->hSubMenu;
4120 /**********************************************************************
4121 * DrawMenuBar16 (USER.160)
4123 void WINAPI DrawMenuBar16( HWND16 hWnd )
4125 DrawMenuBar( hWnd );
4129 /**********************************************************************
4130 * DrawMenuBar (USER32.161)
4132 BOOL WINAPI DrawMenuBar( HWND hWnd )
4135 WND *wndPtr = WIN_FindWndPtr(hWnd);
4136 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
4138 lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu);
4141 WIN_ReleaseWndPtr(wndPtr);
4145 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4146 lppop->hwndOwner = hWnd;
4147 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4148 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4149 WIN_ReleaseWndPtr(wndPtr);
4152 WIN_ReleaseWndPtr(wndPtr);
4157 /***********************************************************************
4158 * EndMenu (USER.187) (USER32.175)
4160 void WINAPI EndMenu(void)
4163 * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
4170 /***********************************************************************
4171 * LookupMenuHandle (USER.217)
4173 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4175 HMENU hmenu32 = hmenu;
4177 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4178 else return hmenu32;
4182 /**********************************************************************
4183 * LoadMenu16 (USER.150)
4185 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, SEGPTR name )
4193 char *str = (char *)PTR_SEG_TO_LIN( name );
4194 TRACE("(%04x,'%s')\n", instance, str );
4195 if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
4198 TRACE("(%04x,%04x)\n",instance,LOWORD(name));
4200 if (!name) return 0;
4202 /* check for Win32 module */
4203 if (HIWORD(instance))
4204 return LoadMenuA(instance,PTR_SEG_TO_LIN(name));
4205 instance = GetExePtr( instance );
4207 if (!(hRsrc = FindResource16( instance, name, RT_MENU16 ))) return 0;
4208 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4209 hMenu = LoadMenuIndirect16(LockResource16(handle));
4210 FreeResource16( handle );
4215 /*****************************************************************
4216 * LoadMenuA (USER32.370)
4218 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4220 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4221 if (!hrsrc) return 0;
4222 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4226 /*****************************************************************
4227 * LoadMenuW (USER32.373)
4229 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4231 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4232 if (!hrsrc) return 0;
4233 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4237 /**********************************************************************
4238 * LoadMenuIndirect16 (USER.220)
4240 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4243 WORD version, offset;
4244 LPCSTR p = (LPCSTR)template;
4246 TRACE("(%p)\n", template );
4247 version = GET_WORD(p);
4251 WARN("version must be 0 for Win16\n" );
4254 offset = GET_WORD(p);
4255 p += sizeof(WORD) + offset;
4256 if (!(hMenu = CreateMenu())) return 0;
4257 if (!MENU_ParseResource( p, hMenu, FALSE ))
4259 DestroyMenu( hMenu );
4266 /**********************************************************************
4267 * LoadMenuIndirectA (USER32.371)
4269 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4272 WORD version, offset;
4273 LPCSTR p = (LPCSTR)template;
4275 TRACE("%p\n", template );
4276 version = GET_WORD(p);
4281 offset = GET_WORD(p);
4282 p += sizeof(WORD) + offset;
4283 if (!(hMenu = CreateMenu())) return 0;
4284 if (!MENU_ParseResource( p, hMenu, TRUE ))
4286 DestroyMenu( hMenu );
4291 offset = GET_WORD(p);
4292 p += sizeof(WORD) + offset;
4293 if (!(hMenu = CreateMenu())) return 0;
4294 if (!MENUEX_ParseResource( p, hMenu))
4296 DestroyMenu( hMenu );
4301 ERR("version %d not supported.\n", version);
4307 /**********************************************************************
4308 * LoadMenuIndirectW (USER32.372)
4310 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4312 /* FIXME: is there anything different between A and W? */
4313 return LoadMenuIndirectA( template );
4317 /**********************************************************************
4318 * IsMenu16 (USER.358)
4320 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4322 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4323 return IS_A_MENU(menu);
4327 /**********************************************************************
4328 * IsMenu (USER32.346)
4330 BOOL WINAPI IsMenu(HMENU hmenu)
4332 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4333 return IS_A_MENU(menu);
4336 /**********************************************************************
4337 * GetMenuItemInfo_common
4340 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4341 LPMENUITEMINFOA lpmii, BOOL unicode)
4343 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4345 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4350 if (lpmii->fMask & MIIM_TYPE) {
4351 lpmii->fType = menu->fType;
4352 switch (MENU_ITEM_TYPE(menu->fType)) {
4355 int len = lstrlenA(menu->text);
4356 if(lpmii->dwTypeData && lpmii->cch) {
4358 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4361 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4362 /* if we've copied a substring we return its length */
4363 if(lpmii->cch <= len)
4365 } else /* return length of string */
4371 lpmii->dwTypeData = menu->text;
4378 if (lpmii->fMask & MIIM_STRING) {
4379 if(lpmii->dwTypeData && lpmii->cch) {
4381 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4384 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4386 lpmii->cch = lstrlenA(menu->text);
4389 if (lpmii->fMask & MIIM_FTYPE)
4390 lpmii->fType = menu->fType;
4392 if (lpmii->fMask & MIIM_BITMAP)
4393 lpmii->hbmpItem = menu->hbmpItem;
4395 if (lpmii->fMask & MIIM_STATE)
4396 lpmii->fState = menu->fState;
4398 if (lpmii->fMask & MIIM_ID)
4399 lpmii->wID = menu->wID;
4401 if (lpmii->fMask & MIIM_SUBMENU)
4402 lpmii->hSubMenu = menu->hSubMenu;
4404 if (lpmii->fMask & MIIM_CHECKMARKS) {
4405 lpmii->hbmpChecked = menu->hCheckBit;
4406 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4408 if (lpmii->fMask & MIIM_DATA)
4409 lpmii->dwItemData = menu->dwItemData;
4414 /**********************************************************************
4415 * GetMenuItemInfoA (USER32.264)
4417 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4418 LPMENUITEMINFOA lpmii)
4420 return GetMenuItemInfo_common (hmenu, item, bypos, lpmii, FALSE);
4423 /**********************************************************************
4424 * GetMenuItemInfoW (USER32.265)
4426 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4427 LPMENUITEMINFOW lpmii)
4429 return GetMenuItemInfo_common (hmenu, item, bypos,
4430 (LPMENUITEMINFOA)lpmii, TRUE);
4433 /**********************************************************************
4434 * SetMenuItemInfo_common
4437 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4438 const MENUITEMINFOA *lpmii,
4441 if (!menu) return FALSE;
4443 if (lpmii->fMask & MIIM_TYPE ) {
4444 /* Get rid of old string. */
4445 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4446 HeapFree(SystemHeap, 0, menu->text);
4450 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4451 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4452 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4454 menu->text = lpmii->dwTypeData;
4456 if (IS_STRING_ITEM(menu->fType) && menu->text) {
4458 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4460 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4464 if (lpmii->fMask & MIIM_FTYPE ) {
4465 /* free the string when the type is changing */
4466 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4467 HeapFree(SystemHeap, 0, menu->text);
4470 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4471 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4474 if (lpmii->fMask & MIIM_STRING ) {
4475 /* free the string when used */
4476 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4477 HeapFree(SystemHeap, 0, menu->text);
4479 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4481 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4485 if (lpmii->fMask & MIIM_STATE)
4487 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4488 menu->fState = lpmii->fState;
4491 if (lpmii->fMask & MIIM_ID)
4492 menu->wID = lpmii->wID;
4494 if (lpmii->fMask & MIIM_SUBMENU) {
4495 menu->hSubMenu = lpmii->hSubMenu;
4496 if (menu->hSubMenu) {
4497 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4499 subMenu->wFlags |= MF_POPUP;
4500 menu->fType |= MF_POPUP;
4503 /* FIXME: Return an error ? */
4504 menu->fType &= ~MF_POPUP;
4507 menu->fType &= ~MF_POPUP;
4510 if (lpmii->fMask & MIIM_CHECKMARKS)
4512 menu->hCheckBit = lpmii->hbmpChecked;
4513 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4515 if (lpmii->fMask & MIIM_DATA)
4516 menu->dwItemData = lpmii->dwItemData;
4518 debug_print_menuitem("SetMenuItemInfo_common: ", menu, "");
4522 /**********************************************************************
4523 * SetMenuItemInfoA (USER32.491)
4525 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4526 const MENUITEMINFOA *lpmii)
4528 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4532 /**********************************************************************
4533 * SetMenuItemInfoW (USER32.492)
4535 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4536 const MENUITEMINFOW *lpmii)
4538 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4539 (const MENUITEMINFOA*)lpmii, TRUE);
4542 /**********************************************************************
4543 * SetMenuDefaultItem (USER32.489)
4546 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4552 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4554 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4556 /* reset all default-item flags */
4558 for (i = 0; i < menu->nItems; i++, item++)
4560 item->fState &= ~MFS_DEFAULT;
4563 /* no default item */
4572 if ( uItem >= menu->nItems ) return FALSE;
4573 item[uItem].fState |= MFS_DEFAULT;
4578 for (i = 0; i < menu->nItems; i++, item++)
4580 if (item->wID == uItem)
4582 item->fState |= MFS_DEFAULT;
4591 /**********************************************************************
4592 * GetMenuDefaultItem (USER32.260)
4594 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4600 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4602 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4604 /* find default item */
4608 if (! item) return -1;
4610 while ( !( item->fState & MFS_DEFAULT ) )
4613 if (i >= menu->nItems ) return -1;
4616 /* default: don't return disabled items */
4617 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4619 /* search rekursiv when needed */
4620 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4623 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4624 if ( -1 != ret ) return ret;
4626 /* when item not found in submenu, return the popup item */
4628 return ( bypos ) ? i : item->wID;
4632 /*******************************************************************
4633 * InsertMenuItem16 (USER.441)
4637 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4638 const MENUITEMINFO16 *mii )
4642 miia.cbSize = sizeof(miia);
4643 miia.fMask = mii->fMask;
4644 miia.dwTypeData = mii->dwTypeData;
4645 miia.fType = mii->fType;
4646 miia.fState = mii->fState;
4647 miia.wID = mii->wID;
4648 miia.hSubMenu = mii->hSubMenu;
4649 miia.hbmpChecked = mii->hbmpChecked;
4650 miia.hbmpUnchecked = mii->hbmpUnchecked;
4651 miia.dwItemData = mii->dwItemData;
4652 miia.cch = mii->cch;
4653 if (IS_STRING_ITEM(miia.fType))
4654 miia.dwTypeData = PTR_SEG_TO_LIN(miia.dwTypeData);
4655 return InsertMenuItemA( hmenu, pos, byposition, &miia );
4659 /**********************************************************************
4660 * InsertMenuItemA (USER32.323)
4662 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4663 const MENUITEMINFOA *lpmii)
4665 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4666 return SetMenuItemInfo_common(item, lpmii, FALSE);
4670 /**********************************************************************
4671 * InsertMenuItemW (USER32.324)
4673 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4674 const MENUITEMINFOW *lpmii)
4676 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4677 return SetMenuItemInfo_common(item, (const MENUITEMINFOA*)lpmii, TRUE);
4680 /**********************************************************************
4681 * CheckMenuRadioItem (USER32.47)
4684 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4685 UINT first, UINT last, UINT check,
4688 MENUITEM *mifirst, *milast, *micheck;
4689 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4691 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4692 hMenu, first, last, check, bypos);
4694 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4695 milast = MENU_FindItem (&mlast, &last, bypos);
4696 micheck = MENU_FindItem (&mcheck, &check, bypos);
4698 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4699 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4700 micheck > milast || micheck < mifirst)
4703 while (mifirst <= milast)
4705 if (mifirst == micheck)
4707 mifirst->fType |= MFT_RADIOCHECK;
4708 mifirst->fState |= MFS_CHECKED;
4710 mifirst->fType &= ~MFT_RADIOCHECK;
4711 mifirst->fState &= ~MFS_CHECKED;
4719 /**********************************************************************
4720 * CheckMenuRadioItem16 (not a Windows API)
4723 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4724 UINT16 first, UINT16 last, UINT16 check,
4727 return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4730 /**********************************************************************
4731 * GetMenuItemRect (USER32.266)
4733 * ATTENTION: Here, the returned values in rect are the screen
4734 * coordinates of the item just like if the menu was
4735 * always on the upper left side of the application.
4738 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4741 POPUPMENU *itemMenu;
4745 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4747 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4748 referenceHwnd = hwnd;
4752 itemMenu = MENU_GetMenu(hMenu);
4753 if (itemMenu == NULL)
4756 if(itemMenu->hWnd == 0)
4758 referenceHwnd = itemMenu->hWnd;
4761 if ((rect == NULL) || (item == NULL))
4766 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4771 /**********************************************************************
4772 * GetMenuItemRect16 (USER.665)
4775 BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
4781 if (!rect) return FALSE;
4782 res = GetMenuItemRect (hwnd, hMenu, uItem, &r32);
4783 CONV_RECT32TO16 (&r32, rect);
4787 /**********************************************************************
4791 * MIM_APPLYTOSUBMENUS
4792 * actually use the items to draw the menu
4794 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4798 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4800 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4803 if (lpmi->fMask & MIM_BACKGROUND)
4804 menu->hbrBack = lpmi->hbrBack;
4806 if (lpmi->fMask & MIM_HELPID)
4807 menu->dwContextHelpID = lpmi->dwContextHelpID;
4809 if (lpmi->fMask & MIM_MAXHEIGHT)
4810 menu->cyMax = lpmi->cyMax;
4812 if (lpmi->fMask & MIM_MENUDATA)
4813 menu->dwMenuData = lpmi->dwMenuData;
4815 if (lpmi->fMask & MIM_STYLE)
4816 menu->dwStyle = lpmi->dwStyle;
4823 /**********************************************************************
4830 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4833 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4835 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4838 if (lpmi->fMask & MIM_BACKGROUND)
4839 lpmi->hbrBack = menu->hbrBack;
4841 if (lpmi->fMask & MIM_HELPID)
4842 lpmi->dwContextHelpID = menu->dwContextHelpID;
4844 if (lpmi->fMask & MIM_MAXHEIGHT)
4845 lpmi->cyMax = menu->cyMax;
4847 if (lpmi->fMask & MIM_MENUDATA)
4848 lpmi->dwMenuData = menu->dwMenuData;
4850 if (lpmi->fMask & MIM_STYLE)
4851 lpmi->dwStyle = menu->dwStyle;
4858 /**********************************************************************
4859 * SetMenuContextHelpId16 (USER.384)
4861 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4863 return SetMenuContextHelpId( hMenu, dwContextHelpID );
4867 /**********************************************************************
4868 * SetMenuContextHelpId (USER32.488)
4870 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4874 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4876 if ((menu = MENU_GetMenu(hMenu)))
4878 menu->dwContextHelpID = dwContextHelpID;
4884 /**********************************************************************
4885 * GetMenuContextHelpId16 (USER.385)
4887 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4889 return GetMenuContextHelpId( hMenu );
4892 /**********************************************************************
4893 * GetMenuContextHelpId (USER32.488)
4895 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4899 TRACE("(0x%04x)\n", hMenu);
4901 if ((menu = MENU_GetMenu(hMenu)))
4903 return menu->dwContextHelpID;
4908 /**********************************************************************
4909 * MenuItemFromPoint (USER32.387)
4911 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4913 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4914 hWnd, hMenu, ptScreen.x, ptScreen.y);