While dragging, catch keyboard messages between WM_KEYFIRST and
[wine.git] / controls / menu.c
blob568b25049bbdc5b4ebcf1ab9184ac1daf8148850
1 /*
2 * Menu functions
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
7 */
9 /*
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.
15 #include <assert.h>
16 #include <ctype.h>
17 #include <stdlib.h>
18 #include <string.h>
20 #include "windef.h"
21 #include "wingdi.h"
22 #include "wine/winbase16.h"
23 #include "wine/winuser16.h"
24 #include "win.h"
25 #include "task.h"
26 #include "heap.h"
27 #include "menu.h"
28 #include "nonclient.h"
29 #include "user.h"
30 #include "message.h"
31 #include "queue.h"
32 #include "tweak.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 */
45 typedef struct {
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 */
60 } MENUITEM;
62 /* Popup menu structure */
63 typedef struct {
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
90 typedef struct
92 UINT trackFlags;
93 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
94 HMENU hTopMenu; /* initial menu */
95 HWND hOwnerWnd; /* where notifications are sent */
96 POINT pt;
97 } MTRACKER;
99 #define MENU_MAGIC 0x554d /* 'MU' */
100 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
102 #define ITEM_PREV -1
103 #define ITEM_NEXT 1
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) \
191 do { \
192 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
193 } while (0)
195 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
196 const char *postfix)
198 TRACE("%s ", prefix);
199 if (mp) {
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);
205 if (flags) {
206 int count = 0;
207 DPRINTF( ", Typ=");
208 if (typ == MFT_STRING)
209 /* Nothing */ ;
210 else if (typ == MFT_SEPARATOR)
211 MENUOUT("sep");
212 else if (typ == MFT_OWNERDRAW)
213 MENUOUT("own");
214 else if (typ == MFT_BITMAP)
215 MENUOUT("bit");
216 else
217 MENUOUT("???");
218 flags -= typ;
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 */
228 if (flags)
229 DPRINTF( "+0x%x", flags);
231 flags = mp->fState;
232 if (flags) {
233 int count = 0;
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");
242 if (flags)
243 DPRINTF( "+0x%x", flags);
245 if (mp->hCheckBit)
246 DPRINTF( ", Chk=0x%x", mp->hCheckBit);
247 if (mp->hUnCheckBit)
248 DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
250 if (typ == MFT_STRING) {
251 if (mp->text)
252 DPRINTF( ", Text=\"%s\"", mp->text);
253 else
254 DPRINTF( ", Text=Null");
255 } else if (mp->text == NULL)
256 /* Nothing */ ;
257 else
258 DPRINTF( ", Text=%p", mp->text);
259 if (mp->dwItemData)
260 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
261 DPRINTF( " }");
262 } else {
263 DPRINTF( "NULL");
266 DPRINTF(" %s\n", postfix);
269 #undef MENUOUT
270 #undef MENUFLAG
273 /***********************************************************************
274 * MENU_GetMenu
276 * Validate the given menu handle and returns the menu structure pointer.
278 POPUPMENU *MENU_GetMenu(HMENU hMenu)
280 POPUPMENU *menu;
281 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
282 if (!IS_A_MENU(menu))
284 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
285 menu = NULL;
287 return menu;
290 /***********************************************************************
291 * MENU_CopySysPopup
293 * Return the default system menu.
295 static HMENU MENU_CopySysPopup(void)
297 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
299 if( hMenu ) {
300 POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
301 menu->wFlags |= MF_SYSMENU | MF_POPUP;
302 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
304 else {
305 hMenu = 0;
306 ERR("Unable to load default system menu\n" );
309 TRACE("returning %x.\n", hMenu );
311 return 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;
340 pTopPopupWnd = NULL;
341 WIN_ReleaseWndPtr(tmpWnd);
346 /**********************************************************************
347 * MENU_GetSysMenu
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 )
357 HMENU hMenu;
359 if ((hMenu = CreateMenu()))
361 POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
362 menu->wFlags = MF_SYSMENU;
363 menu->hWnd = hWnd;
365 if (hPopupMenu == (HMENU)(-1))
366 hPopupMenu = MENU_CopySysPopup();
367 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
369 if (hPopupMenu)
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 );
379 return hMenu;
381 DestroyMenu( hMenu );
383 ERR("failed to load system menu!\n");
384 return 0;
388 /***********************************************************************
389 * MENU_Init
391 * Menus initialisation.
393 BOOL MENU_Init()
395 HBITMAP hBitmap;
396 NONCLIENTMETRICSA ncm;
398 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
399 0x55, 0, 0xAA, 0,
400 0x55, 0, 0xAA, 0,
401 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));
415 if (hStdCheck)
417 BITMAP bm;
418 GetObjectA( hStdCheck, sizeof(bm), &bm );
419 check_bitmap_width = bm.bmWidth;
420 check_bitmap_height = bm.bmHeight;
421 } else
422 return FALSE;
424 /* Assume that radio checks have the same size as regular check. */
425 if (!hStdRadioCheck)
426 return FALSE;
428 if (hStdMnArrow)
430 BITMAP bm;
431 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
432 arrow_bitmap_width = bm.bmWidth;
433 arrow_bitmap_height = bm.bmHeight;
434 } else
435 return FALSE;
437 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
438 return FALSE;
440 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
441 return FALSE;
443 DeleteObject( hBitmap );
444 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
445 return FALSE;
447 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
448 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
449 return FALSE;
451 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
452 return FALSE;
454 ncm.lfMenuFont.lfWeight += 300;
455 if ( ncm.lfMenuFont.lfWeight > 1000)
456 ncm.lfMenuFont.lfWeight = 1000;
458 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
459 return FALSE;
461 return TRUE;
464 /***********************************************************************
465 * MENU_InitSysMenuPopup
467 * Grey the appropriate items in System menu.
469 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
471 BOOL gray;
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 */
486 if(gray)
487 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
491 /******************************************************************************
493 * UINT MENU_GetStartOfNextColumn(
494 * HMENU hMenu )
496 *****************************************************************************/
498 static UINT MENU_GetStartOfNextColumn(
499 HMENU hMenu )
501 POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
502 UINT i = menu->FocusedItem + 1;
504 if(!menu)
505 return NO_SELECTED_ITEM;
507 if( i == NO_SELECTED_ITEM )
508 return i;
510 for( ; i < menu->nItems; ++i ) {
511 if (menu->items[i].fType & MF_MENUBARBREAK)
512 return i;
515 return NO_SELECTED_ITEM;
519 /******************************************************************************
521 * UINT MENU_GetStartOfPrevColumn(
522 * HMENU hMenu )
524 *****************************************************************************/
526 static UINT MENU_GetStartOfPrevColumn(
527 HMENU hMenu )
529 POPUPMENU const *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
530 UINT i;
532 if( !menu )
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);
542 --i); /* empty */
544 if(i == 0)
545 return NO_SELECTED_ITEM;
547 for(--i; i != 0; --i) {
548 if (menu->items[i].fType & MF_MENUBARBREAK)
549 break;
552 TRACE("ret %d.\n", i );
554 return i;
559 /***********************************************************************
560 * MENU_FindItem
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 )
567 POPUPMENU *menu;
568 UINT i;
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];
576 else
578 MENUITEM *item = menu->items;
579 for (i = 0; i < menu->nItems; i++, item++)
581 if (item->wID == *nPos)
583 *nPos = i;
584 return item;
586 else if (item->fType & MF_POPUP)
588 HMENU hsubmenu = item->hSubMenu;
589 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
590 if (subitem)
592 *hmenu = hsubmenu;
593 return subitem;
598 return NULL;
601 /***********************************************************************
602 * MENU_FindSubMenu
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 )
610 POPUPMENU *menu;
611 UINT i;
612 MENUITEM *item;
613 if (((*hmenu)==0xffff) ||
614 (!(menu = MENU_GetMenu(*hmenu))))
615 return NO_SELECTED_ITEM;
616 item = menu->items;
617 for (i = 0; i < menu->nItems; i++, item++) {
618 if(!(item->fType & MF_POPUP)) continue;
619 if (item->hSubMenu == hSubTarget) {
620 return i;
622 else {
623 HMENU hsubmenu = item->hSubMenu;
624 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
625 if (pos != NO_SELECTED_ITEM) {
626 *hmenu = hsubmenu;
627 return pos;
631 return NO_SELECTED_ITEM;
634 /***********************************************************************
635 * MENU_FreeItemData
637 static void MENU_FreeItemData( MENUITEM* item )
639 /* delete text */
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 )
654 MENUITEM *item;
655 UINT i;
656 RECT wrect;
658 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
659 pt.x -= wrect.left;pt.y -= wrect.top;
660 item = menu->items;
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))
666 if (pos) *pos = i;
667 return item;
670 return NULL;
674 /***********************************************************************
675 * MENU_FindItemByKey
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);
692 if (hmenu)
694 POPUPMENU *menu = MENU_GetMenu( hmenu );
695 MENUITEM *item = menu->items;
696 LONG menuchar;
698 if( !forceMenuChar )
700 UINT i;
702 key = toupper(key);
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);
722 return (UINT)(-1);
724 /***********************************************************************
725 * MENU_LoadMagicItem
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.
740 switch(id & 0xffff)
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:
758 default:
759 FIXME("Magic 0x%08x not implemented\n", id);
760 return 0;
765 /***********************************************************************
766 * MENU_CalcItemSize
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 )
773 char *p;
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;
792 mis.CtlID = 0;
793 mis.itemID = lpitem->wID;
794 mis.itemData = (DWORD)lpitem->dwItemData;
795 mis.itemHeight = 0;
796 mis.itemWidth = 0;
797 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
798 lpitem->rect.right += mis.itemWidth;
800 if (menuBar)
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);
810 else
811 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
813 else
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;
824 return;
827 if (!menuBar)
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)
835 return;
837 if (IS_BITMAP_ITEM(lpitem->fType))
839 BITMAP bm;
840 HBITMAP resBmp = 0;
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),
846 lpitem->dwItemData);
848 else
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 ))
862 { SIZE size;
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) );
869 else
870 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
871 lpitem->xTab = 0;
873 if (menuBar)
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;
884 else
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 )
903 MENUITEM *lpitem;
904 HDC hdc;
905 int start, i;
906 int orgX, orgY, maxX, maxTab, maxTabWidth;
908 lppop->Width = lppop->Height = 0;
909 if (lppop->nItems == 0) return;
910 hdc = GetDC( 0 );
912 SelectObject( hdc, hMenuFont);
914 start = 0;
915 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2 ;
917 while (start < lppop->nItems)
919 lpitem = &lppop->items[start];
920 orgX = maxX;
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++)
928 if ((i != start) &&
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 );
955 lppop->Width = maxX;
957 /* space for 3d border */
958 if(TWEAK_WineLook > WIN31_LOOK)
960 lppop->Height += 2;
961 lppop->Width += 2;
964 ReleaseDC( 0, hdc );
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 )
980 MENUITEM *lpitem;
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;
988 lppop->Height = 0;
989 maxY = lprect->top;
990 start = 0;
991 helpPos = -1;
992 while (start < lppop->nItems)
994 lpitem = &lppop->items[start];
995 orgX = lprect->left;
996 orgY = maxY;
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;
1002 if ((i != start) &&
1003 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1005 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1006 orgX, orgY );
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) ))
1034 break; /* done */
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 /***********************************************************************
1044 * MENU_DrawMenuItem
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 )
1051 RECT rect;
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,
1060 lpitem->fState &
1061 (MF_HILITE | MF_MOUSESELECT) );
1062 else
1063 NC_DrawSysButton( hwnd, hdc,
1064 lpitem->fState &
1065 (MF_HILITE | MF_MOUSESELECT) );
1068 return;
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.
1082 DRAWITEMSTRUCT dis;
1084 dis.CtlType = ODT_MENU;
1085 dis.CtlID = 0;
1086 dis.itemID = lpitem->wID;
1087 dis.itemData = (DWORD)lpitem->dwItemData;
1088 dis.itemState = 0;
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;
1094 dis.hDC = hdc;
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,
1100 dis.rcItem.bottom);
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);
1117 else
1118 FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
1119 else
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)
1132 RECT rc = rect;
1133 rc.top = 3;
1134 rc.bottom = height - 3;
1135 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1137 else
1139 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1140 MoveToEx( hdc, rect.left, 0, NULL );
1141 LineTo( hdc, rect.left, height );
1145 /* horizontal separator */
1146 if (lpitem->fType & MF_SEPARATOR)
1148 if (TWEAK_WineLook > WIN31_LOOK)
1150 RECT rc = rect;
1151 rc.left++;
1152 rc.right--;
1153 rc.top += SEPARATOR_HEIGHT / 2;
1154 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1156 else
1158 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1159 MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
1160 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1162 return;
1166 /* Setup colors */
1168 if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)) )
1170 if (lpitem->fState & MF_GRAYED)
1171 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1172 else
1173 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
1174 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
1176 else
1178 if (lpitem->fState & MF_GRAYED)
1179 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1180 else
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 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1189 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1192 if (!menuBar)
1194 INT y = rect.top + rect.bottom;
1196 if (!(lpitem->fType & MF_OWNERDRAW))
1198 /* Draw the check mark
1200 * FIXME:
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 );
1214 DeleteDC( hdcMem );
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 );
1224 DeleteDC( hdcMem );
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 );
1240 DeleteDC( hdcMem );
1243 rect.left += check_bitmap_width;
1244 rect.right -= arrow_bitmap_width;
1247 /* Done for owner-drawn */
1248 if (lpitem->fType & MF_OWNERDRAW)
1249 return;
1251 /* Draw the item text or bitmap */
1252 if (IS_BITMAP_ITEM(lpitem->fType))
1253 { int top;
1255 HBITMAP resBmp = 0;
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);
1268 else
1269 resBmp = (HBITMAP)lpitem->text;
1271 if (resBmp)
1273 BITMAP bm;
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 );
1285 DeleteDC( hdcMem );
1287 return;
1290 /* No bitmap - process text if present */
1291 else if (IS_STRING_ITEM(lpitem->fType))
1293 register int i;
1294 HFONT hfontOld = 0;
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);
1305 if (menuBar)
1307 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1308 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1309 i = strlen( lpitem->text );
1311 else
1313 for (i = 0; lpitem->text[i]; i++)
1314 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1315 break;
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;
1340 else
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 );
1359 if (hfontOld)
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;
1373 RECT rect;
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)))
1388 HPEN hPrevPen;
1390 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1392 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1393 if( hPrevPen )
1395 INT ropPrev, i;
1396 POPUPMENU *menu;
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 );
1409 i = rect.bottom;
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 );
1417 else
1418 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1420 /* draw menu items */
1422 menu = MENU_GetMenu( hmenu );
1423 if (menu && menu->nItems)
1425 MENUITEM *item;
1426 UINT u;
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 );
1433 } else
1435 SelectObject( hdc, hPrevBrush );
1440 /***********************************************************************
1441 * MENU_DrawMenuBar
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,
1447 BOOL suppress_draw)
1449 LPPOPUPMENU lppop;
1450 UINT i,retvalue;
1451 HFONT hfontOld = 0;
1453 WND *wndPtr = WIN_FindWndPtr( hwnd );
1455 lppop = MENU_GetMenu ((HMENU)wndPtr->wIDmenu );
1456 if (lppop == NULL || lprect == NULL)
1458 retvalue = GetSystemMetrics(SM_CYMENU);
1459 goto END;
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;
1471 if (suppress_draw)
1473 retvalue = lppop->Height;
1474 goto END;
1477 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1479 if (TWEAK_WineLook == WIN31_LOOK)
1481 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1482 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1483 LineTo( hDC, lprect->right, lprect->bottom );
1485 else
1487 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1488 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1489 LineTo( hDC, lprect->right, lprect->bottom );
1492 if (lppop->nItems == 0)
1494 retvalue = GetSystemMetrics(SM_CYMENU);
1495 goto END;
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;
1505 END:
1506 if (hfontOld)
1507 SelectObject (hDC, hfontOld);
1509 WIN_ReleaseWndPtr(wndPtr);
1510 return retvalue;
1513 /***********************************************************************
1514 * MENU_PatchResidentPopup
1516 BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
1518 WND *pTPWnd = MENU_GetTopPopupWnd();
1520 if( pTPWnd )
1522 HTASK16 hTask = 0;
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 */
1531 if( checkWnd )
1533 pTPWnd->owner = checkWnd;
1534 if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
1535 hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
1537 break;
1539 case 0xFFFF: /* checkWnd is destroyed */
1540 if( pTPWnd->owner == checkWnd )
1541 pTPWnd->owner = NULL;
1542 MENU_ReleaseTopPopupWnd();
1543 return TRUE;
1545 default: /* checkQueue is exiting */
1546 if( pTPWnd->hmemTaskQ == checkQueue )
1548 hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
1549 hTask = TASK_GetNextTask( hTask );
1551 break;
1554 if( hTask )
1556 TDB* task = (TDB*)GlobalLock16( hTask );
1557 if( task )
1559 pTPWnd->hInstance = task->hInstance;
1560 pTPWnd->hmemTaskQ = task->hQueue;
1561 MENU_ReleaseTopPopupWnd();
1562 return TRUE;
1564 else WARN("failed to patch resident popup.\n");
1567 MENU_ReleaseTopPopupWnd();
1568 return FALSE;
1571 /***********************************************************************
1572 * MENU_ShowPopup
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 )
1579 POPUPMENU *menu;
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 )) )
1597 UINT width, height;
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 ))
1608 if( xanchor )
1609 x -= width - xanchor;
1610 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1611 x = GetSystemMetrics(SM_CXSCREEN) - width;
1613 if( x < 0 ) x = 0;
1615 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1617 if( yanchor )
1618 y -= height + yanchor;
1619 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1620 y = GetSystemMetrics(SM_CYSCREEN) - height;
1622 if( y < 0 ) y = 0;
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,
1638 (LPVOID)hmenu ));
1639 if (!pTopPopupWnd)
1641 WIN_ReleaseWndPtr(wndOwner);
1642 return FALSE;
1644 menu->hWnd = pTopPopupWnd->hwndSelf;
1645 MENU_ReleaseTopPopupWnd();
1647 else
1648 if( uSubPWndLevel )
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,
1655 (LPVOID)hmenu );
1656 if( !menu->hWnd )
1658 WIN_ReleaseWndPtr(wndOwner);
1659 return FALSE;
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);
1685 return TRUE;
1687 return FALSE;
1691 /***********************************************************************
1692 * MENU_SelectItem
1694 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1695 BOOL sendMenuSelect, HMENU topmenu )
1697 LPPOPUPMENU lppop;
1698 HDC hdc;
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),
1717 ODA_SELECT );
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 );
1730 if (sendMenuSelect)
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) {
1740 if(topmenu){
1741 int pos;
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 )
1764 INT i;
1765 POPUPMENU *menu;
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
1776 ; i += offset)
1777 if (!(menu->items[i].fType & MF_SEPARATOR))
1779 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1780 return;
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 );
1789 return;
1794 /**********************************************************************
1795 * MENU_SetItemData
1797 * Set an item flags, id and text ptr. Called by InsertMenu() and
1798 * ModifyMenu().
1800 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1801 LPCSTR str )
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))
1809 if (!str || !*str)
1811 flags |= MF_SEPARATOR;
1812 item->text = NULL;
1814 else
1816 LPSTR text;
1817 /* Item beginning with a backspace is a help item */
1818 if (*str == '\b')
1820 flags |= MF_HELP;
1821 str++;
1823 if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1824 item->text = text;
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;
1833 else
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;
1843 else
1845 item->wID = 0;
1846 item->hSubMenu = 0;
1847 item->fType = 0;
1848 item->fState = 0;
1849 return FALSE;
1853 item->wID = id;
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, "");
1871 return TRUE;
1875 /**********************************************************************
1876 * MENU_InsertItem
1878 * Insert a new item into a menu.
1880 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1882 MENUITEM *newItems;
1883 POPUPMENU *menu;
1885 if (!(menu = MENU_GetMenu(hMenu)))
1886 return NULL;
1888 /* Find where to insert new item */
1890 if (flags & MF_BYPOSITION) {
1891 if (pos > menu->nItems)
1892 pos = menu->nItems;
1893 } else {
1894 if (!MENU_FindItem( &hMenu, &pos, flags ))
1895 pos = menu->nItems;
1896 else {
1897 if (!(menu = MENU_GetMenu( hMenu )))
1898 return NULL;
1902 /* Create new items array */
1904 newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1905 if (!newItems)
1907 WARN("allocation failed\n" );
1908 return NULL;
1910 if (menu->nItems > 0)
1912 /* Copy the old array into the new */
1913 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1914 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1915 (menu->nItems-pos)*sizeof(MENUITEM) );
1916 HeapFree( SystemHeap, 0, menu->items );
1918 menu->items = newItems;
1919 menu->nItems++;
1920 memset( &newItems[pos], 0, sizeof(*newItems) );
1921 menu->Height = 0; /* force size recalculate */
1922 return &newItems[pos];
1926 /**********************************************************************
1927 * MENU_ParseResource
1929 * Parse a standard menu resource and add items to the menu.
1930 * Return a pointer to the end of the resource.
1932 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1934 WORD flags, id = 0;
1935 LPCSTR str;
1939 flags = GET_WORD(res);
1940 res += sizeof(WORD);
1941 if (!(flags & MF_POPUP))
1943 id = GET_WORD(res);
1944 res += sizeof(WORD);
1946 if (!IS_STRING_ITEM(flags))
1947 ERR("not a string item %04x\n", flags );
1948 str = res;
1949 if (!unicode) res += strlen(str) + 1;
1950 else res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1951 if (flags & MF_POPUP)
1953 HMENU hSubMenu = CreatePopupMenu();
1954 if (!hSubMenu) return NULL;
1955 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1956 return NULL;
1957 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1958 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1960 else /* Not a popup */
1962 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1963 else AppendMenuW( hMenu, flags, id,
1964 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1966 } while (!(flags & MF_END));
1967 return res;
1971 /**********************************************************************
1972 * MENUEX_ParseResource
1974 * Parse an extended menu resource and add items to the menu.
1975 * Return a pointer to the end of the resource.
1977 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1979 WORD resinfo;
1980 do {
1981 MENUITEMINFOW mii;
1983 mii.cbSize = sizeof(mii);
1984 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1985 mii.fType = GET_DWORD(res);
1986 res += sizeof(DWORD);
1987 mii.fState = GET_DWORD(res);
1988 res += sizeof(DWORD);
1989 mii.wID = GET_DWORD(res);
1990 res += sizeof(DWORD);
1991 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1992 res += sizeof(WORD);
1993 /* Align the text on a word boundary. */
1994 res += (~((int)res - 1)) & 1;
1995 mii.dwTypeData = (LPWSTR) res;
1996 res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
1997 /* Align the following fields on a dword boundary. */
1998 res += (~((int)res - 1)) & 3;
2000 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2002 LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
2003 0, mii.dwTypeData);
2004 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2005 mii.fType, mii.fState, mii.wID, resinfo, newstr);
2006 HeapFree( GetProcessHeap(), 0, newstr );
2009 if (resinfo & 1) { /* Pop-up? */
2010 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2011 res += sizeof(DWORD);
2012 mii.hSubMenu = CreatePopupMenu();
2013 if (!mii.hSubMenu)
2014 return NULL;
2015 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2016 DestroyMenu(mii.hSubMenu);
2017 return NULL;
2019 mii.fMask |= MIIM_SUBMENU;
2020 mii.fType |= MF_POPUP;
2022 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2023 } while (!(resinfo & MF_END));
2024 return res;
2028 /***********************************************************************
2029 * MENU_GetSubPopup
2031 * Return the handle of the selected sub-popup menu (if any).
2033 static HMENU MENU_GetSubPopup( HMENU hmenu )
2035 POPUPMENU *menu;
2036 MENUITEM *item;
2038 menu = MENU_GetMenu( hmenu );
2040 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2042 item = &menu->items[menu->FocusedItem];
2043 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2044 return item->hSubMenu;
2045 return 0;
2049 /***********************************************************************
2050 * MENU_HideSubPopups
2052 * Hide the sub-popup menus of this menu.
2054 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2055 BOOL sendMenuSelect )
2057 POPUPMENU *menu = MENU_GetMenu( hmenu );
2059 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2061 if (menu && uSubPWndLevel)
2063 HMENU hsubmenu;
2064 POPUPMENU *submenu;
2065 MENUITEM *item;
2067 if (menu->FocusedItem != NO_SELECTED_ITEM)
2069 item = &menu->items[menu->FocusedItem];
2070 if (!(item->fType & MF_POPUP) ||
2071 !(item->fState & MF_MOUSESELECT)) return;
2072 item->fState &= ~MF_MOUSESELECT;
2073 hsubmenu = item->hSubMenu;
2074 } else return;
2076 submenu = MENU_GetMenu( hsubmenu );
2077 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2078 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2080 if (submenu->hWnd == MENU_GetTopPopupWnd()->hwndSelf )
2082 ShowWindow( submenu->hWnd, SW_HIDE );
2083 uSubPWndLevel = 0;
2085 else
2087 DestroyWindow( submenu->hWnd );
2088 submenu->hWnd = 0;
2090 MENU_ReleaseTopPopupWnd();
2095 /***********************************************************************
2096 * MENU_ShowSubPopup
2098 * Display the sub-menu of the selected item of this menu.
2099 * Return the handle of the submenu, or hmenu if no submenu to display.
2101 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2102 BOOL selectFirst, UINT wFlags )
2104 RECT rect;
2105 POPUPMENU *menu;
2106 MENUITEM *item;
2107 WND *wndPtr;
2108 HDC hdc;
2110 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2112 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2114 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
2115 (menu->FocusedItem == NO_SELECTED_ITEM))
2117 WIN_ReleaseWndPtr(wndPtr);
2118 return hmenu;
2121 item = &menu->items[menu->FocusedItem];
2122 if (!(item->fType & MF_POPUP) ||
2123 (item->fState & (MF_GRAYED | MF_DISABLED)))
2125 WIN_ReleaseWndPtr(wndPtr);
2126 return hmenu;
2129 /* message must be send before using item,
2130 because nearly everything may by changed by the application ! */
2132 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2133 if (!(wFlags & TPM_NONOTIFY))
2134 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2135 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2137 item = &menu->items[menu->FocusedItem];
2138 rect = item->rect;
2140 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2141 if (!(item->fState & MF_HILITE))
2143 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2144 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2146 SelectObject( hdc, hMenuFont);
2148 item->fState |= MF_HILITE;
2149 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2150 ReleaseDC( menu->hWnd, hdc );
2152 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2153 item->rect = rect;
2155 item->fState |= MF_MOUSESELECT;
2157 if (IS_SYSTEM_MENU(menu))
2159 MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, GetClassLongA(wndPtr->hwndSelf, GCL_STYLE));
2161 NC_GetSysPopupPos( wndPtr, &rect );
2162 rect.top = rect.bottom;
2163 rect.right = GetSystemMetrics(SM_CXSIZE);
2164 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2166 else
2168 if (menu->wFlags & MF_POPUP)
2170 rect.left = wndPtr->rectWindow.left + item->rect.right - GetSystemMetrics(SM_CXBORDER);
2171 rect.top = wndPtr->rectWindow.top + item->rect.top;
2172 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2173 rect.bottom = item->rect.top - item->rect.bottom;
2175 else
2177 rect.left = wndPtr->rectWindow.left + item->rect.left;
2178 rect.top = wndPtr->rectWindow.top + item->rect.bottom;
2179 rect.right = item->rect.right - item->rect.left;
2180 rect.bottom = item->rect.bottom - item->rect.top;
2184 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2185 rect.left, rect.top, rect.right, rect.bottom );
2186 if (selectFirst)
2187 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2188 WIN_ReleaseWndPtr(wndPtr);
2189 return item->hSubMenu;
2194 /**********************************************************************
2195 * MENU_IsMenuActive
2197 BOOL MENU_IsMenuActive(void)
2199 return pTopPopupWnd && (pTopPopupWnd->dwStyle & WS_VISIBLE);
2202 /***********************************************************************
2203 * MENU_PtMenu
2205 * Walks menu chain trying to find a menu pt maps to.
2207 static HMENU MENU_PtMenu( HMENU hMenu, POINT16 pt )
2209 POPUPMENU *menu = MENU_GetMenu( hMenu );
2210 register UINT ht = menu->FocusedItem;
2212 /* try subpopup first (if any) */
2213 ht = (ht != NO_SELECTED_ITEM &&
2214 (menu->items[ht].fType & MF_POPUP) &&
2215 (menu->items[ht].fState & MF_MOUSESELECT))
2216 ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
2218 if( !ht ) /* check the current window (avoiding WM_HITTEST) */
2220 ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt );
2221 if( menu->wFlags & MF_POPUP )
2222 ht = (ht != (UINT)HTNOWHERE &&
2223 ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
2224 else
2226 WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
2228 ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu)
2229 : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0;
2230 WIN_ReleaseWndPtr(wndPtr);
2233 return (HMENU)ht;
2236 /***********************************************************************
2237 * MENU_ExecFocusedItem
2239 * Execute a menu item (for instance when user pressed Enter).
2240 * Return the wID of the executed item. Otherwise, -1 indicating
2241 * that no menu item was executed;
2242 * Have to receive the flags for the TrackPopupMenu options to avoid
2243 * sending unwanted message.
2246 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2248 MENUITEM *item;
2249 POPUPMENU *menu = MENU_GetMenu( hMenu );
2251 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2253 if (!menu || !menu->nItems ||
2254 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2256 item = &menu->items[menu->FocusedItem];
2258 TRACE("%08x %08x %08x\n",
2259 hMenu, item->wID, item->hSubMenu);
2261 if (!(item->fType & MF_POPUP))
2263 if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
2265 /* If TPM_RETURNCMD is set you return the id, but
2266 do not send a message to the owner */
2267 if(!(wFlags & TPM_RETURNCMD))
2269 if( menu->wFlags & MF_SYSMENU )
2270 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2271 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2272 else
2273 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2275 return item->wID;
2278 else
2279 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2281 return -1;
2284 /***********************************************************************
2285 * MENU_SwitchTracking
2287 * Helper function for menu navigation routines.
2289 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2291 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2292 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2294 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2296 if( pmt->hTopMenu != hPtMenu &&
2297 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2299 /* both are top level menus (system and menu-bar) */
2300 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2301 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2302 pmt->hTopMenu = hPtMenu;
2304 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2305 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2309 /***********************************************************************
2310 * MENU_ButtonDown
2312 * Return TRUE if we can go on with menu tracking.
2314 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2316 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2318 if (hPtMenu)
2320 UINT id = 0;
2321 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2322 MENUITEM *item;
2324 if( IS_SYSTEM_MENU(ptmenu) )
2325 item = ptmenu->items;
2326 else
2327 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2329 if( item )
2331 if( ptmenu->FocusedItem != id )
2332 MENU_SwitchTracking( pmt, hPtMenu, id );
2334 /* If the popup menu is not already "popped" */
2335 if(!(item->fState & MF_MOUSESELECT ))
2337 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2339 /* In win31, a newly popped menu always remain opened for the next buttonup */
2340 if(TWEAK_WineLook == WIN31_LOOK)
2341 ptmenu->bTimeToHide = FALSE;
2344 return TRUE;
2346 /* Else the click was on the menu bar, finish the tracking */
2348 return FALSE;
2351 /***********************************************************************
2352 * MENU_ButtonUp
2354 * Return the value of MENU_ExecFocusedItem if
2355 * the selected item was not a popup. Else open the popup.
2356 * A -1 return value indicates that we go on with menu tracking.
2359 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2361 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2363 if (hPtMenu)
2365 UINT id = 0;
2366 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2367 MENUITEM *item;
2369 if( IS_SYSTEM_MENU(ptmenu) )
2370 item = ptmenu->items;
2371 else
2372 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2374 if( item && (ptmenu->FocusedItem == id ))
2376 if( !(item->fType & MF_POPUP) )
2377 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2379 /* If we are dealing with the top-level menu and that this */
2380 /* is a click on an already "poppped" item */
2381 /* Stop the menu tracking and close the opened submenus */
2382 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2383 return 0;
2385 ptmenu->bTimeToHide = TRUE;
2387 return -1;
2391 /***********************************************************************
2392 * MENU_MouseMove
2394 * Return TRUE if we can go on with menu tracking.
2396 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2398 UINT id = NO_SELECTED_ITEM;
2399 POPUPMENU *ptmenu = NULL;
2401 if( hPtMenu )
2403 ptmenu = MENU_GetMenu( hPtMenu );
2404 if( IS_SYSTEM_MENU(ptmenu) )
2405 id = 0;
2406 else
2407 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2410 if( id == NO_SELECTED_ITEM )
2412 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2413 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2416 else if( ptmenu->FocusedItem != id )
2418 MENU_SwitchTracking( pmt, hPtMenu, id );
2419 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2421 return TRUE;
2425 /***********************************************************************
2426 * MENU_DoNextMenu
2428 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2430 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2432 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2434 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2435 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2437 WND* wndPtr;
2438 HMENU hNewMenu;
2439 HWND hNewWnd;
2440 UINT id = 0;
2441 LRESULT l = SendMessageA( pmt->hOwnerWnd, WM_NEXTMENU, vk,
2442 (IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
2444 TRACE("%04x [%04x] -> %04x [%04x]\n",
2445 (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
2447 if( l == 0 )
2449 wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
2451 hNewWnd = pmt->hOwnerWnd;
2452 if( IS_SYSTEM_MENU(menu) )
2454 /* switch to the menu bar */
2456 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
2458 WIN_ReleaseWndPtr(wndPtr);
2459 return FALSE;
2462 hNewMenu = wndPtr->wIDmenu;
2463 if( vk == VK_LEFT )
2465 menu = MENU_GetMenu( hNewMenu );
2466 id = menu->nItems - 1;
2469 else if( wndPtr->dwStyle & WS_SYSMENU )
2471 /* switch to the system menu */
2472 hNewMenu = wndPtr->hSysMenu;
2474 else
2476 WIN_ReleaseWndPtr(wndPtr);
2477 return FALSE;
2479 WIN_ReleaseWndPtr(wndPtr);
2481 else /* application returned a new menu to switch to */
2483 hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
2485 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2487 wndPtr = WIN_FindWndPtr(hNewWnd);
2489 if( wndPtr->dwStyle & WS_SYSMENU &&
2490 GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
2492 /* get the real system menu */
2493 hNewMenu = wndPtr->hSysMenu;
2495 else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
2497 /* FIXME: Not sure what to do here, perhaps,
2498 * try to track hNewMenu as a popup? */
2500 TRACE(" -- got confused.\n");
2501 WIN_ReleaseWndPtr(wndPtr);
2502 return FALSE;
2504 WIN_ReleaseWndPtr(wndPtr);
2506 else return FALSE;
2509 if( hNewMenu != pmt->hTopMenu )
2511 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2512 FALSE, 0 );
2513 if( pmt->hCurrentMenu != pmt->hTopMenu )
2514 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2517 if( hNewWnd != pmt->hOwnerWnd )
2519 ReleaseCapture();
2520 pmt->hOwnerWnd = hNewWnd;
2521 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2524 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2525 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2527 return TRUE;
2529 return FALSE;
2532 /***********************************************************************
2533 * MENU_SuspendPopup
2535 * The idea is not to show the popup if the next input message is
2536 * going to hide it anyway.
2538 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2540 MSG msg;
2542 msg.hwnd = pmt->hOwnerWnd;
2544 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2545 pmt->trackFlags |= TF_SKIPREMOVE;
2547 switch( uMsg )
2549 case WM_KEYDOWN:
2550 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2551 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2553 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2554 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2555 if( msg.message == WM_KEYDOWN &&
2556 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2558 pmt->trackFlags |= TF_SUSPENDPOPUP;
2559 return TRUE;
2562 break;
2565 /* failures go through this */
2566 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2567 return FALSE;
2570 /***********************************************************************
2571 * MENU_KeyLeft
2573 * Handle a VK_LEFT key event in a menu.
2575 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2577 POPUPMENU *menu;
2578 HMENU hmenutmp, hmenuprev;
2579 UINT prevcol;
2581 hmenuprev = hmenutmp = pmt->hTopMenu;
2582 menu = MENU_GetMenu( hmenutmp );
2584 /* Try to move 1 column left (if possible) */
2585 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2586 NO_SELECTED_ITEM ) {
2588 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2589 prevcol, TRUE, 0 );
2590 return;
2593 /* close topmost popup */
2594 while (hmenutmp != pmt->hCurrentMenu)
2596 hmenuprev = hmenutmp;
2597 hmenutmp = MENU_GetSubPopup( hmenuprev );
2600 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2601 pmt->hCurrentMenu = hmenuprev;
2603 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2605 /* move menu bar selection if no more popups are left */
2607 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2608 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2610 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2612 /* A sublevel menu was displayed - display the next one
2613 * unless there is another displacement coming up */
2615 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2616 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2617 pmt->hTopMenu, TRUE, wFlags);
2623 /***********************************************************************
2624 * MENU_KeyRight
2626 * Handle a VK_RIGHT key event in a menu.
2628 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2630 HMENU hmenutmp;
2631 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2632 UINT nextcol;
2634 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2635 pmt->hCurrentMenu,
2636 (MENU_GetMenu(pmt->hCurrentMenu))->
2637 items[0].text,
2638 pmt->hTopMenu, menu->items[0].text );
2640 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2642 /* If already displaying a popup, try to display sub-popup */
2644 hmenutmp = pmt->hCurrentMenu;
2645 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2647 /* if subpopup was displayed then we are done */
2648 if (hmenutmp != pmt->hCurrentMenu) return;
2651 /* Check to see if there's another column */
2652 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2653 NO_SELECTED_ITEM ) {
2654 TRACE("Going to %d.\n", nextcol );
2655 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2656 nextcol, TRUE, 0 );
2657 return;
2660 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2662 if( pmt->hCurrentMenu != pmt->hTopMenu )
2664 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2665 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2666 } else hmenutmp = 0;
2668 /* try to move to the next item */
2669 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2670 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2672 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2673 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2674 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2675 pmt->hTopMenu, TRUE, wFlags);
2679 /***********************************************************************
2680 * MENU_TrackMenu
2682 * Menu tracking code.
2684 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2685 HWND hwnd, const RECT *lprect )
2687 MSG msg;
2688 POPUPMENU *menu;
2689 BOOL fRemove;
2690 INT executedMenuId = -1;
2691 MTRACKER mt;
2692 BOOL enterIdleSent = FALSE;
2694 mt.trackFlags = 0;
2695 mt.hCurrentMenu = hmenu;
2696 mt.hTopMenu = hmenu;
2697 mt.hOwnerWnd = hwnd;
2698 mt.pt.x = x;
2699 mt.pt.y = y;
2701 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2702 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2703 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2705 fEndMenu = FALSE;
2706 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2708 if (wFlags & TPM_BUTTONDOWN)
2710 /* Get the result in order to start the tracking or not */
2711 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2712 fEndMenu = !fRemove;
2715 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2717 while (!fEndMenu)
2719 menu = MENU_GetMenu( mt.hCurrentMenu );
2720 msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2722 /* we have to keep the message in the queue until it's
2723 * clear that menu loop is not over yet. */
2725 if (!MSG_InternalGetMessage( QMSG_WIN32A, &msg, msg.hwnd, mt.hOwnerWnd,
2726 MSGF_MENU, PM_NOREMOVE, !enterIdleSent, &enterIdleSent )) break;
2728 /* check if EndMenu() tried to cancel us, by posting this message */
2729 if(msg.message == WM_CANCELMODE)
2731 /* we are now out of the loop */
2732 fEndMenu = TRUE;
2734 /* remove the message from the queue */
2735 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2737 /* break out of internal loop, ala ESCAPE */
2738 break;
2741 TranslateMessage( &msg );
2742 mt.pt = msg.pt;
2744 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2745 enterIdleSent=FALSE;
2747 fRemove = FALSE;
2748 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2750 /* Find a menu for this mouse event */
2751 POINT16 pt16;
2752 CONV_POINT32TO16( &msg.pt, &pt16 );
2753 hmenu = MENU_PtMenu( mt.hTopMenu, pt16 );
2755 switch(msg.message)
2757 /* no WM_NC... messages in captured state */
2759 case WM_RBUTTONDBLCLK:
2760 case WM_RBUTTONDOWN:
2761 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2762 /* fall through */
2763 case WM_LBUTTONDBLCLK:
2764 case WM_LBUTTONDOWN:
2765 /* If the message belongs to the menu, removes it from the queue */
2766 /* Else, end menu tracking */
2767 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2768 fEndMenu = !fRemove;
2769 break;
2771 case WM_RBUTTONUP:
2772 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2773 /* fall through */
2774 case WM_LBUTTONUP:
2775 /* Check if a menu was selected by the mouse */
2776 if (hmenu)
2778 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2780 /* End the loop if executedMenuId is an item ID */
2781 /* or if the job was done (executedMenuId = 0). */
2782 fEndMenu = fRemove = (executedMenuId != -1);
2784 /* No menu was selected by the mouse */
2785 /* if the function was called by TrackPopupMenu, continue
2786 with the menu tracking. If not, stop it */
2787 else
2788 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2790 break;
2792 case WM_MOUSEMOVE:
2793 /* In win95 winelook, the selected menu item must be changed every time the
2794 mouse moves. In Win31 winelook, the mouse button has to be held down */
2796 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2797 ( (msg.wParam & MK_LBUTTON) ||
2798 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2800 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2802 } /* switch(msg.message) - mouse */
2804 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2806 fRemove = TRUE; /* Keyboard messages are always removed */
2807 switch(msg.message)
2809 case WM_KEYDOWN:
2810 switch(msg.wParam)
2812 case VK_HOME:
2813 case VK_END:
2814 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2815 NO_SELECTED_ITEM, FALSE, 0 );
2816 /* fall through */
2817 case VK_UP:
2818 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2819 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2820 break;
2822 case VK_DOWN: /* If on menu bar, pull-down the menu */
2824 menu = MENU_GetMenu( mt.hCurrentMenu );
2825 if (!(menu->wFlags & MF_POPUP))
2826 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2827 else /* otherwise try to move selection */
2828 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2829 break;
2831 case VK_LEFT:
2832 MENU_KeyLeft( &mt, wFlags );
2833 break;
2835 case VK_RIGHT:
2836 MENU_KeyRight( &mt, wFlags );
2837 break;
2839 case VK_ESCAPE:
2840 fEndMenu = TRUE;
2841 break;
2843 case VK_F1:
2845 HELPINFO hi;
2846 hi.cbSize = sizeof(HELPINFO);
2847 hi.iContextType = HELPINFO_MENUITEM;
2848 if (menu->FocusedItem == NO_SELECTED_ITEM)
2849 hi.iCtrlId = 0;
2850 else
2851 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2852 hi.hItemHandle = hmenu;
2853 hi.dwContextId = menu->dwContextHelpID;
2854 hi.MousePos = msg.pt;
2855 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2856 break;
2859 default:
2860 break;
2862 break; /* WM_KEYDOWN */
2864 case WM_SYSKEYDOWN:
2865 switch(msg.wParam)
2867 case VK_MENU:
2868 fEndMenu = TRUE;
2869 break;
2872 break; /* WM_SYSKEYDOWN */
2874 case WM_CHAR:
2876 UINT pos;
2878 if (msg.wParam == '\r' || msg.wParam == ' ')
2880 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2881 fEndMenu = (executedMenuId != -1);
2883 break;
2886 /* Hack to avoid control chars. */
2887 /* We will find a better way real soon... */
2888 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2890 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
2891 LOWORD(msg.wParam), FALSE );
2892 if (pos == (UINT)-2) fEndMenu = TRUE;
2893 else if (pos == (UINT)-1) MessageBeep(0);
2894 else
2896 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2897 TRUE, 0 );
2898 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2899 fEndMenu = (executedMenuId != -1);
2902 break;
2903 } /* switch(msg.message) - kbd */
2905 else
2907 DispatchMessageA( &msg );
2910 if (!fEndMenu) fRemove = TRUE;
2912 /* finally remove message from the queue */
2914 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2915 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2916 else mt.trackFlags &= ~TF_SKIPREMOVE;
2919 ReleaseCapture();
2921 /* If dropdown is still painted and the close box is clicked on
2922 then the menu will be destroyed as part of the DispatchMessage above.
2923 This will then invalidate the menu handle in mt.hTopMenu. We should
2924 check for this first. */
2925 if( IsMenu( mt.hTopMenu ) )
2927 menu = MENU_GetMenu( mt.hTopMenu );
2929 if( IsWindow( mt.hOwnerWnd ) )
2931 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2933 if (menu && menu->wFlags & MF_POPUP)
2935 ShowWindow( menu->hWnd, SW_HIDE );
2936 uSubPWndLevel = 0;
2938 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2939 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2942 /* Reset the variable for hiding menu */
2943 if( menu ) menu->bTimeToHide = FALSE;
2946 /* The return value is only used by TrackPopupMenu */
2947 return ((executedMenuId != -1) ? executedMenuId : 0);
2950 /***********************************************************************
2951 * MENU_InitTracking
2953 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
2955 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
2957 HideCaret(0);
2959 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2960 if (!(wFlags & TPM_NONOTIFY))
2961 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2963 SendMessageA( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
2965 if (!(wFlags & TPM_NONOTIFY))
2966 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
2968 return TRUE;
2970 /***********************************************************************
2971 * MENU_ExitTracking
2973 static BOOL MENU_ExitTracking(HWND hWnd)
2975 TRACE("hwnd=0x%04x\n", hWnd);
2977 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2978 ShowCaret(0);
2979 return TRUE;
2982 /***********************************************************************
2983 * MENU_TrackMouseMenuBar
2985 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2987 void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt )
2989 HWND hWnd = wndPtr->hwndSelf;
2990 HMENU hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
2991 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2993 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr, ht, pt.x, pt.y);
2995 if (IsMenu(hMenu))
2997 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2998 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
2999 MENU_ExitTracking(hWnd);
3004 /***********************************************************************
3005 * MENU_TrackKbdMenuBar
3007 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3009 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
3011 UINT uItem = NO_SELECTED_ITEM;
3012 HMENU hTrackMenu;
3013 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3015 /* find window that has a menu */
3017 while( wndPtr->dwStyle & WS_CHILD)
3018 if( !(wndPtr = wndPtr->parent) ) return;
3020 /* check if we have to track a system menu */
3022 if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) ||
3023 !wndPtr->wIDmenu || vkey == VK_SPACE )
3025 if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
3026 hTrackMenu = wndPtr->hSysMenu;
3027 uItem = 0;
3028 wParam |= HTSYSMENU; /* prevent item lookup */
3030 else
3031 hTrackMenu = wndPtr->wIDmenu;
3033 if (IsMenu( hTrackMenu ))
3035 MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu, FALSE, wFlags );
3037 if( vkey && vkey != VK_SPACE )
3039 uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu,
3040 vkey, (wParam & HTSYSMENU) );
3041 if( uItem >= (UINT)(-2) )
3043 if( uItem == (UINT)(-1) ) MessageBeep(0);
3044 hTrackMenu = 0;
3048 if( hTrackMenu )
3050 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE, 0 );
3052 if( uItem == NO_SELECTED_ITEM )
3053 MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
3054 else if( vkey )
3055 PostMessageA( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
3057 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, wndPtr->hwndSelf, NULL );
3060 MENU_ExitTracking (wndPtr->hwndSelf);
3065 /**********************************************************************
3066 * TrackPopupMenu16 (USER.416)
3068 BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
3069 INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
3071 RECT r;
3072 if (lpRect)
3073 CONV_RECT16TO32( lpRect, &r );
3074 return TrackPopupMenu( hMenu, wFlags, x, y, nReserved, hWnd,
3075 lpRect ? &r : NULL );
3079 /**********************************************************************
3080 * TrackPopupMenu (USER32.549)
3082 * Like the win32 API, the function return the command ID only if the
3083 * flag TPM_RETURNCMD is on.
3086 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3087 INT nReserved, HWND hWnd, const RECT *lpRect )
3089 BOOL ret = FALSE;
3091 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3093 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3094 if (!(wFlags & TPM_NONOTIFY))
3095 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3097 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3098 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3099 MENU_ExitTracking(hWnd);
3101 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3102 ret = 1;
3104 return ret;
3107 /**********************************************************************
3108 * TrackPopupMenuEx (USER32.550)
3110 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3111 HWND hWnd, LPTPMPARAMS lpTpm )
3113 FIXME("not fully implemented\n" );
3114 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3115 lpTpm ? &lpTpm->rcExclude : NULL );
3118 /***********************************************************************
3119 * PopupMenuWndProc
3121 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3123 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
3124 LPARAM lParam )
3126 WND* wndPtr = WIN_FindWndPtr(hwnd);
3127 LRESULT retvalue;
3129 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3130 hwnd, message, wParam, lParam);
3132 switch(message)
3134 case WM_CREATE:
3136 CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
3137 SetWindowLongA( hwnd, 0, (LONG)cs->lpCreateParams );
3138 retvalue = 0;
3139 goto END;
3142 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3143 retvalue = MA_NOACTIVATE;
3144 goto END;
3146 case WM_PAINT:
3148 PAINTSTRUCT ps;
3149 BeginPaint( hwnd, &ps );
3150 MENU_DrawPopupMenu( hwnd, ps.hdc,
3151 (HMENU)GetWindowLongA( hwnd, 0 ) );
3152 EndPaint( hwnd, &ps );
3153 retvalue = 0;
3154 goto END;
3156 case WM_ERASEBKGND:
3157 retvalue = 1;
3158 goto END;
3160 case WM_DESTROY:
3162 /* zero out global pointer in case resident popup window
3163 * was somehow destroyed. */
3165 if(MENU_GetTopPopupWnd() )
3167 if( hwnd == pTopPopupWnd->hwndSelf )
3169 ERR("resident popup destroyed!\n");
3171 MENU_DestroyTopPopupWnd();
3172 uSubPWndLevel = 0;
3174 else
3175 uSubPWndLevel--;
3176 MENU_ReleaseTopPopupWnd();
3178 break;
3180 case WM_SHOWWINDOW:
3182 if( wParam )
3184 if( !(*(HMENU*)wndPtr->wExtra) )
3185 ERR("no menu to display\n");
3187 else
3188 *(HMENU*)wndPtr->wExtra = 0;
3189 break;
3191 case MM_SETMENUHANDLE:
3193 *(HMENU*)wndPtr->wExtra = (HMENU)wParam;
3194 break;
3196 case MM_GETMENUHANDLE:
3198 retvalue = *(HMENU*)wndPtr->wExtra;
3199 goto END;
3201 default:
3202 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
3203 goto END;
3205 retvalue = 0;
3206 END:
3207 WIN_ReleaseWndPtr(wndPtr);
3208 return retvalue;
3212 /***********************************************************************
3213 * MENU_GetMenuBarHeight
3215 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3217 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3218 INT orgX, INT orgY )
3220 HDC hdc;
3221 RECT rectBar;
3222 WND *wndPtr;
3223 LPPOPUPMENU lppop;
3224 UINT retvalue;
3226 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3227 hwnd, menubarWidth, orgX, orgY );
3229 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
3230 return 0;
3232 if (!(lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu)))
3234 WIN_ReleaseWndPtr(wndPtr);
3235 return 0;
3238 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3239 SelectObject( hdc, hMenuFont);
3240 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3241 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3242 ReleaseDC( hwnd, hdc );
3243 retvalue = lppop->Height;
3244 WIN_ReleaseWndPtr(wndPtr);
3245 return retvalue;
3249 /*******************************************************************
3250 * ChangeMenu16 (USER.153)
3252 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3253 UINT16 id, UINT16 flags )
3255 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3256 hMenu, pos, (DWORD)data, id, flags );
3257 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3258 id, data );
3260 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3261 /* for MF_DELETE. We should check the parameters for all others */
3262 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3264 if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3265 if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3266 id, data );
3267 if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
3268 flags & MF_BYPOSITION ? pos : id,
3269 flags & ~MF_REMOVE );
3270 /* Default: MF_INSERT */
3271 return InsertMenu16( hMenu, pos, flags, id, data );
3275 /*******************************************************************
3276 * ChangeMenuA (USER32.23)
3278 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3279 UINT id, UINT flags )
3281 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3282 hMenu, pos, (DWORD)data, id, flags );
3283 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3284 id, data );
3285 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3286 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3287 id, data );
3288 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3289 flags & MF_BYPOSITION ? pos : id,
3290 flags & ~MF_REMOVE );
3291 /* Default: MF_INSERT */
3292 return InsertMenuA( hMenu, pos, flags, id, data );
3296 /*******************************************************************
3297 * ChangeMenuW (USER32.24)
3299 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3300 UINT id, UINT flags )
3302 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3303 hMenu, pos, (DWORD)data, id, flags );
3304 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3305 id, data );
3306 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3307 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3308 id, data );
3309 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3310 flags & MF_BYPOSITION ? pos : id,
3311 flags & ~MF_REMOVE );
3312 /* Default: MF_INSERT */
3313 return InsertMenuW( hMenu, pos, flags, id, data );
3317 /*******************************************************************
3318 * CheckMenuItem16 (USER.154)
3320 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
3322 return (BOOL16)CheckMenuItem( hMenu, id, flags );
3326 /*******************************************************************
3327 * CheckMenuItem (USER32.46)
3329 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3331 MENUITEM *item;
3332 DWORD ret;
3334 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3335 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3336 ret = item->fState & MF_CHECKED;
3337 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3338 else item->fState &= ~MF_CHECKED;
3339 return ret;
3343 /**********************************************************************
3344 * EnableMenuItem16 (USER.155)
3346 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3348 return EnableMenuItem( hMenu, wItemID, wFlags );
3352 /**********************************************************************
3353 * EnableMenuItem (USER32.170)
3355 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3357 UINT oldflags;
3358 MENUITEM *item;
3359 POPUPMENU *menu;
3361 TRACE("(%04x, %04X, %04X) !\n",
3362 hMenu, wItemID, wFlags);
3364 /* Get the Popupmenu to access the owner menu */
3365 if (!(menu = MENU_GetMenu(hMenu)))
3366 return (UINT)-1;
3368 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3369 return (UINT)-1;
3371 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3372 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3374 /* In win95 if the close item in the system menu change update the close button */
3375 if (TWEAK_WineLook == WIN95_LOOK)
3376 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3378 if (menu->hSysMenuOwner != 0)
3380 POPUPMENU* parentMenu;
3382 /* Get the parent menu to access*/
3383 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3384 return (UINT)-1;
3386 /* Refresh the frame to reflect the change*/
3387 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3388 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3392 return oldflags;
3396 /*******************************************************************
3397 * GetMenuString16 (USER.161)
3399 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3400 LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
3402 return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
3406 /*******************************************************************
3407 * GetMenuStringA (USER32.268)
3409 INT WINAPI GetMenuStringA(
3410 HMENU hMenu, /* [in] menuhandle */
3411 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3412 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3413 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3414 UINT wFlags /* [in] MF_ flags */
3416 MENUITEM *item;
3418 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3419 hMenu, wItemID, str, nMaxSiz, wFlags );
3420 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3421 if (!IS_STRING_ITEM(item->fType)) return 0;
3422 if (!str || !nMaxSiz) return strlen(item->text);
3423 str[0] = '\0';
3424 lstrcpynA( str, item->text, nMaxSiz );
3425 TRACE("returning '%s'\n", str );
3426 return strlen(str);
3430 /*******************************************************************
3431 * GetMenuStringW (USER32.269)
3433 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3434 LPWSTR str, INT nMaxSiz, UINT wFlags )
3436 MENUITEM *item;
3438 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3439 hMenu, wItemID, str, nMaxSiz, wFlags );
3440 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3441 if (!IS_STRING_ITEM(item->fType)) return 0;
3442 if (!str || !nMaxSiz) return strlen(item->text);
3443 str[0] = '\0';
3444 lstrcpynAtoW( str, item->text, nMaxSiz );
3445 return lstrlenW(str);
3449 /**********************************************************************
3450 * HiliteMenuItem16 (USER.162)
3452 BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
3453 UINT16 wHilite )
3455 return HiliteMenuItem( hWnd, hMenu, wItemID, wHilite );
3459 /**********************************************************************
3460 * HiliteMenuItem (USER32.318)
3462 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3463 UINT wHilite )
3465 LPPOPUPMENU menu;
3466 TRACE("(%04x, %04x, %04x, %04x);\n",
3467 hWnd, hMenu, wItemID, wHilite);
3468 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3469 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3470 if (menu->FocusedItem == wItemID) return TRUE;
3471 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3472 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3473 return TRUE;
3477 /**********************************************************************
3478 * GetMenuState16 (USER.250)
3480 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3482 return GetMenuState( hMenu, wItemID, wFlags );
3486 /**********************************************************************
3487 * GetMenuState (USER32.267)
3489 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3491 MENUITEM *item;
3492 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3493 hMenu, wItemID, wFlags);
3494 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3495 debug_print_menuitem (" item: ", item, "");
3496 if (item->fType & MF_POPUP)
3498 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3499 if (!menu) return -1;
3500 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3502 else
3504 /* We used to (from way back then) mask the result to 0xff. */
3505 /* I don't know why and it seems wrong as the documented */
3506 /* return flag MF_SEPARATOR is outside that mask. */
3507 return (item->fType | item->fState);
3512 /**********************************************************************
3513 * GetMenuItemCount16 (USER.263)
3515 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3517 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3518 if (!menu) return -1;
3519 TRACE("(%04x) returning %d\n",
3520 hMenu, menu->nItems );
3521 return menu->nItems;
3525 /**********************************************************************
3526 * GetMenuItemCount (USER32.262)
3528 INT WINAPI GetMenuItemCount( HMENU hMenu )
3530 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3531 if (!menu) return -1;
3532 TRACE("(%04x) returning %d\n",
3533 hMenu, menu->nItems );
3534 return menu->nItems;
3537 /**********************************************************************
3538 * GetMenuItemID16 (USER.264)
3540 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3542 return (UINT16) GetMenuItemID (hMenu, nPos);
3545 /**********************************************************************
3546 * GetMenuItemID (USER32.263)
3548 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3550 MENUITEM * lpmi;
3552 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3553 if (lpmi->fType & MF_POPUP) return -1;
3554 return lpmi->wID;
3558 /*******************************************************************
3559 * InsertMenu16 (USER.410)
3561 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3562 UINT16 id, SEGPTR data )
3564 UINT pos32 = (UINT)pos;
3565 if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3566 if (IS_STRING_ITEM(flags) && data)
3567 return InsertMenuA( hMenu, pos32, flags, id,
3568 (LPSTR)PTR_SEG_TO_LIN(data) );
3569 return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3573 /*******************************************************************
3574 * InsertMenuA (USER32.322)
3576 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3577 UINT id, LPCSTR str )
3579 MENUITEM *item;
3581 if (IS_STRING_ITEM(flags) && str)
3582 TRACE("hMenu %04x, pos %d, flags %08x, "
3583 "id %04x, str '%s'\n",
3584 hMenu, pos, flags, id, str );
3585 else TRACE("hMenu %04x, pos %d, flags %08x, "
3586 "id %04x, str %08lx (not a string)\n",
3587 hMenu, pos, flags, id, (DWORD)str );
3589 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3591 if (!(MENU_SetItemData( item, flags, id, str )))
3593 RemoveMenu( hMenu, pos, flags );
3594 return FALSE;
3597 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3598 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3600 item->hCheckBit = item->hUnCheckBit = 0;
3601 return TRUE;
3605 /*******************************************************************
3606 * InsertMenuW (USER32.325)
3608 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3609 UINT id, LPCWSTR str )
3611 BOOL ret;
3613 if (IS_STRING_ITEM(flags) && str)
3615 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3616 ret = InsertMenuA( hMenu, pos, flags, id, newstr );
3617 HeapFree( GetProcessHeap(), 0, newstr );
3618 return ret;
3620 else return InsertMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3624 /*******************************************************************
3625 * AppendMenu16 (USER.411)
3627 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3629 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3633 /*******************************************************************
3634 * AppendMenuA (USER32.5)
3636 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3637 UINT id, LPCSTR data )
3639 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3643 /*******************************************************************
3644 * AppendMenuW (USER32.6)
3646 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3647 UINT id, LPCWSTR data )
3649 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3653 /**********************************************************************
3654 * RemoveMenu16 (USER.412)
3656 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3658 return RemoveMenu( hMenu, nPos, wFlags );
3662 /**********************************************************************
3663 * RemoveMenu (USER32.441)
3665 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3667 LPPOPUPMENU menu;
3668 MENUITEM *item;
3670 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3671 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3672 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3674 /* Remove item */
3676 MENU_FreeItemData( item );
3678 if (--menu->nItems == 0)
3680 HeapFree( SystemHeap, 0, menu->items );
3681 menu->items = NULL;
3683 else
3685 while(nPos < menu->nItems)
3687 *item = *(item+1);
3688 item++;
3689 nPos++;
3691 menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
3692 menu->nItems * sizeof(MENUITEM) );
3694 return TRUE;
3698 /**********************************************************************
3699 * DeleteMenu16 (USER.413)
3701 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3703 return DeleteMenu( hMenu, nPos, wFlags );
3707 /**********************************************************************
3708 * DeleteMenu (USER32.129)
3710 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3712 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3713 if (!item) return FALSE;
3714 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3715 /* nPos is now the position of the item */
3716 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3717 return TRUE;
3721 /*******************************************************************
3722 * ModifyMenu16 (USER.414)
3724 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3725 UINT16 id, SEGPTR data )
3727 if (IS_STRING_ITEM(flags))
3728 return ModifyMenuA( hMenu, pos, flags, id,
3729 (LPSTR)PTR_SEG_TO_LIN(data) );
3730 return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3734 /*******************************************************************
3735 * ModifyMenuA (USER32.397)
3737 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3738 UINT id, LPCSTR str )
3740 MENUITEM *item;
3742 if (IS_STRING_ITEM(flags))
3744 TRACE("%04x %d %04x %04x '%s'\n",
3745 hMenu, pos, flags, id, str ? str : "#NULL#" );
3746 if (!str) return FALSE;
3748 else
3750 TRACE("%04x %d %04x %04x %08lx\n",
3751 hMenu, pos, flags, id, (DWORD)str );
3754 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3755 return MENU_SetItemData( item, flags, id, str );
3759 /*******************************************************************
3760 * ModifyMenuW (USER32.398)
3762 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3763 UINT id, LPCWSTR str )
3765 BOOL ret;
3767 if (IS_STRING_ITEM(flags) && str)
3769 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3770 ret = ModifyMenuA( hMenu, pos, flags, id, newstr );
3771 HeapFree( GetProcessHeap(), 0, newstr );
3772 return ret;
3774 else return ModifyMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3778 /**********************************************************************
3779 * CreatePopupMenu16 (USER.415)
3781 HMENU16 WINAPI CreatePopupMenu16(void)
3783 return CreatePopupMenu();
3787 /**********************************************************************
3788 * CreatePopupMenu (USER32.82)
3790 HMENU WINAPI CreatePopupMenu(void)
3792 HMENU hmenu;
3793 POPUPMENU *menu;
3795 if (!(hmenu = CreateMenu())) return 0;
3796 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
3797 menu->wFlags |= MF_POPUP;
3798 menu->bTimeToHide = FALSE;
3799 return hmenu;
3803 /**********************************************************************
3804 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3806 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3808 return MAKELONG( check_bitmap_width, check_bitmap_height );
3812 /**********************************************************************
3813 * SetMenuItemBitmaps16 (USER.418)
3815 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3816 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3818 return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3822 /**********************************************************************
3823 * SetMenuItemBitmaps (USER32.490)
3825 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3826 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3828 MENUITEM *item;
3829 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3830 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3831 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3833 if (!hNewCheck && !hNewUnCheck)
3835 item->fState &= ~MF_USECHECKBITMAPS;
3837 else /* Install new bitmaps */
3839 item->hCheckBit = hNewCheck;
3840 item->hUnCheckBit = hNewUnCheck;
3841 item->fState |= MF_USECHECKBITMAPS;
3843 return TRUE;
3847 /**********************************************************************
3848 * CreateMenu16 (USER.151)
3850 HMENU16 WINAPI CreateMenu16(void)
3852 return CreateMenu();
3856 /**********************************************************************
3857 * CreateMenu (USER32.81)
3859 HMENU WINAPI CreateMenu(void)
3861 HMENU hMenu;
3862 LPPOPUPMENU menu;
3863 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3864 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3866 ZeroMemory(menu, sizeof(POPUPMENU));
3867 menu->wMagic = MENU_MAGIC;
3868 menu->FocusedItem = NO_SELECTED_ITEM;
3869 menu->bTimeToHide = FALSE;
3871 TRACE("return %04x\n", hMenu );
3873 return hMenu;
3877 /**********************************************************************
3878 * DestroyMenu16 (USER.152)
3880 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3882 return DestroyMenu( hMenu );
3886 /**********************************************************************
3887 * DestroyMenu (USER32.134)
3889 BOOL WINAPI DestroyMenu( HMENU hMenu )
3891 TRACE("(%04x)\n", hMenu);
3893 /* Silently ignore attempts to destroy default system popup */
3895 if (hMenu && hMenu != MENU_DefSysPopup)
3897 LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3898 WND *pTPWnd = MENU_GetTopPopupWnd();
3900 if( pTPWnd && (hMenu == *(HMENU*)pTPWnd->wExtra) )
3901 *(UINT*)pTPWnd->wExtra = 0;
3903 if (!IS_A_MENU(lppop)) lppop = NULL;
3904 if ( lppop )
3906 lppop->wMagic = 0; /* Mark it as destroyed */
3908 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
3909 (!pTPWnd || (lppop->hWnd != pTPWnd->hwndSelf)))
3910 DestroyWindow( lppop->hWnd );
3912 if (lppop->items) /* recursively destroy submenus */
3914 int i;
3915 MENUITEM *item = lppop->items;
3916 for (i = lppop->nItems; i > 0; i--, item++)
3918 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3919 MENU_FreeItemData( item );
3921 HeapFree( SystemHeap, 0, lppop->items );
3923 USER_HEAP_FREE( hMenu );
3924 MENU_ReleaseTopPopupWnd();
3926 else
3928 MENU_ReleaseTopPopupWnd();
3929 return FALSE;
3932 return (hMenu != MENU_DefSysPopup);
3936 /**********************************************************************
3937 * GetSystemMenu16 (USER.156)
3939 HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
3941 return GetSystemMenu( hWnd, bRevert );
3945 /**********************************************************************
3946 * GetSystemMenu (USER32.291)
3948 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3950 WND *wndPtr = WIN_FindWndPtr( hWnd );
3951 HMENU retvalue = 0;
3953 if (wndPtr)
3955 if( wndPtr->hSysMenu )
3957 if( bRevert )
3959 DestroyMenu(wndPtr->hSysMenu);
3960 wndPtr->hSysMenu = 0;
3962 else
3964 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3965 if( menu )
3967 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3968 menu->items[0].hSubMenu = MENU_CopySysPopup();
3970 else
3972 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3973 wndPtr->hSysMenu, hWnd);
3974 wndPtr->hSysMenu = 0;
3979 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3980 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3982 if( wndPtr->hSysMenu )
3984 POPUPMENU *menu;
3985 retvalue = GetSubMenu16(wndPtr->hSysMenu, 0);
3987 /* Store the dummy sysmenu handle to facilitate the refresh */
3988 /* of the close button if the SC_CLOSE item change */
3989 menu = MENU_GetMenu(retvalue);
3990 if ( menu )
3991 menu->hSysMenuOwner = wndPtr->hSysMenu;
3993 WIN_ReleaseWndPtr(wndPtr);
3995 return bRevert ? 0 : retvalue;
3999 /*******************************************************************
4000 * SetSystemMenu16 (USER.280)
4002 BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
4004 return SetSystemMenu( hwnd, hMenu );
4008 /*******************************************************************
4009 * SetSystemMenu (USER32.508)
4011 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
4013 WND *wndPtr = WIN_FindWndPtr(hwnd);
4015 if (wndPtr)
4017 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
4018 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
4019 WIN_ReleaseWndPtr(wndPtr);
4020 return TRUE;
4022 return FALSE;
4026 /**********************************************************************
4027 * GetMenu16 (USER.157)
4029 HMENU16 WINAPI GetMenu16( HWND16 hWnd )
4031 return (HMENU16)GetMenu(hWnd);
4035 /**********************************************************************
4036 * GetMenu (USER32.257)
4038 HMENU WINAPI GetMenu( HWND hWnd )
4040 HMENU retvalue;
4041 WND * wndPtr = WIN_FindWndPtr(hWnd);
4042 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4044 retvalue = (HMENU)wndPtr->wIDmenu;
4045 goto END;
4047 retvalue = 0;
4048 END:
4049 WIN_ReleaseWndPtr(wndPtr);
4050 return retvalue;
4054 /**********************************************************************
4055 * SetMenu16 (USER.158)
4057 BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
4059 return SetMenu( hWnd, hMenu );
4063 /**********************************************************************
4064 * SetMenu (USER32.487)
4066 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4068 WND * wndPtr = WIN_FindWndPtr(hWnd);
4070 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4072 if (hMenu && !IsMenu(hMenu))
4074 WARN("hMenu is not a menu handle\n");
4075 return FALSE;
4079 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4081 if (GetCapture() == hWnd) ReleaseCapture();
4083 wndPtr->wIDmenu = (UINT)hMenu;
4084 if (hMenu != 0)
4086 LPPOPUPMENU lpmenu;
4088 if (!(lpmenu = MENU_GetMenu(hMenu)))
4090 WIN_ReleaseWndPtr(wndPtr);
4091 return FALSE;
4093 lpmenu->hWnd = hWnd;
4094 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
4095 lpmenu->Height = 0; /* Make sure we recalculate the size */
4097 if (IsWindowVisible(hWnd))
4098 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4099 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4100 WIN_ReleaseWndPtr(wndPtr);
4101 return TRUE;
4103 WIN_ReleaseWndPtr(wndPtr);
4104 return FALSE;
4109 /**********************************************************************
4110 * GetSubMenu16 (USER.159)
4112 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
4114 return GetSubMenu( hMenu, nPos );
4118 /**********************************************************************
4119 * GetSubMenu (USER32.288)
4121 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4123 MENUITEM * lpmi;
4125 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4126 if (!(lpmi->fType & MF_POPUP)) return 0;
4127 return lpmi->hSubMenu;
4131 /**********************************************************************
4132 * DrawMenuBar16 (USER.160)
4134 void WINAPI DrawMenuBar16( HWND16 hWnd )
4136 DrawMenuBar( hWnd );
4140 /**********************************************************************
4141 * DrawMenuBar (USER32.161)
4143 BOOL WINAPI DrawMenuBar( HWND hWnd )
4145 LPPOPUPMENU lppop;
4146 WND *wndPtr = WIN_FindWndPtr(hWnd);
4147 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
4149 lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu);
4150 if (lppop == NULL)
4152 WIN_ReleaseWndPtr(wndPtr);
4153 return FALSE;
4156 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4157 lppop->hwndOwner = hWnd;
4158 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4159 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4160 WIN_ReleaseWndPtr(wndPtr);
4161 return TRUE;
4163 WIN_ReleaseWndPtr(wndPtr);
4164 return FALSE;
4168 /***********************************************************************
4169 * EndMenu (USER.187) (USER32.175)
4171 void WINAPI EndMenu(void)
4173 /* if we are in the menu code, and it is active */
4174 if (fEndMenu == FALSE && MENU_IsMenuActive())
4176 /* terminate the menu handling code */
4177 fEndMenu = TRUE;
4179 /* needs to be posted to wakeup the internal menu handler */
4180 /* which will now terminate the menu, in the event that */
4181 /* the main window was minimized, or lost focus, so we */
4182 /* don't end up with an orphaned menu */
4183 PostMessageA( pTopPopupWnd->hwndSelf, WM_CANCELMODE, 0, 0);
4188 /***********************************************************************
4189 * LookupMenuHandle (USER.217)
4191 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4193 HMENU hmenu32 = hmenu;
4194 UINT id32 = id;
4195 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4196 else return hmenu32;
4200 /**********************************************************************
4201 * LoadMenu16 (USER.150)
4203 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, SEGPTR name )
4205 HRSRC16 hRsrc;
4206 HGLOBAL16 handle;
4207 HMENU16 hMenu;
4209 if (HIWORD(name))
4211 char *str = (char *)PTR_SEG_TO_LIN( name );
4212 TRACE("(%04x,'%s')\n", instance, str );
4213 if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
4215 else
4216 TRACE("(%04x,%04x)\n",instance,LOWORD(name));
4218 if (!name) return 0;
4220 /* check for Win32 module */
4221 if (HIWORD(instance))
4222 return LoadMenuA(instance,PTR_SEG_TO_LIN(name));
4223 instance = GetExePtr( instance );
4225 if (!(hRsrc = FindResource16( instance, name, RT_MENU16 ))) return 0;
4226 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4227 hMenu = LoadMenuIndirect16(LockResource16(handle));
4228 FreeResource16( handle );
4229 return hMenu;
4233 /*****************************************************************
4234 * LoadMenuA (USER32.370)
4236 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4238 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4239 if (!hrsrc) return 0;
4240 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4244 /*****************************************************************
4245 * LoadMenuW (USER32.373)
4247 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4249 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4250 if (!hrsrc) return 0;
4251 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4255 /**********************************************************************
4256 * LoadMenuIndirect16 (USER.220)
4258 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4260 HMENU16 hMenu;
4261 WORD version, offset;
4262 LPCSTR p = (LPCSTR)template;
4264 TRACE("(%p)\n", template );
4265 version = GET_WORD(p);
4266 p += sizeof(WORD);
4267 if (version)
4269 WARN("version must be 0 for Win16\n" );
4270 return 0;
4272 offset = GET_WORD(p);
4273 p += sizeof(WORD) + offset;
4274 if (!(hMenu = CreateMenu())) return 0;
4275 if (!MENU_ParseResource( p, hMenu, FALSE ))
4277 DestroyMenu( hMenu );
4278 return 0;
4280 return hMenu;
4284 /**********************************************************************
4285 * LoadMenuIndirectA (USER32.371)
4287 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4289 HMENU16 hMenu;
4290 WORD version, offset;
4291 LPCSTR p = (LPCSTR)template;
4293 TRACE("%p\n", template );
4294 version = GET_WORD(p);
4295 p += sizeof(WORD);
4296 switch (version)
4298 case 0:
4299 offset = GET_WORD(p);
4300 p += sizeof(WORD) + offset;
4301 if (!(hMenu = CreateMenu())) return 0;
4302 if (!MENU_ParseResource( p, hMenu, TRUE ))
4304 DestroyMenu( hMenu );
4305 return 0;
4307 return hMenu;
4308 case 1:
4309 offset = GET_WORD(p);
4310 p += sizeof(WORD) + offset;
4311 if (!(hMenu = CreateMenu())) return 0;
4312 if (!MENUEX_ParseResource( p, hMenu))
4314 DestroyMenu( hMenu );
4315 return 0;
4317 return hMenu;
4318 default:
4319 ERR("version %d not supported.\n", version);
4320 return 0;
4325 /**********************************************************************
4326 * LoadMenuIndirectW (USER32.372)
4328 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4330 /* FIXME: is there anything different between A and W? */
4331 return LoadMenuIndirectA( template );
4335 /**********************************************************************
4336 * IsMenu16 (USER.358)
4338 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4340 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4341 return IS_A_MENU(menu);
4345 /**********************************************************************
4346 * IsMenu (USER32.346)
4348 BOOL WINAPI IsMenu(HMENU hmenu)
4350 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4351 return IS_A_MENU(menu);
4354 /**********************************************************************
4355 * GetMenuItemInfo_common
4358 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4359 LPMENUITEMINFOA lpmii, BOOL unicode)
4361 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4363 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4365 if (!menu)
4366 return FALSE;
4368 if (lpmii->fMask & MIIM_TYPE) {
4369 lpmii->fType = menu->fType;
4370 switch (MENU_ITEM_TYPE(menu->fType)) {
4371 case MF_STRING:
4372 if (menu->text) {
4373 int len = strlen(menu->text);
4374 if(lpmii->dwTypeData && lpmii->cch) {
4375 if (unicode)
4376 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4377 lpmii->cch);
4378 else
4379 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4380 /* if we've copied a substring we return its length */
4381 if(lpmii->cch <= len)
4382 lpmii->cch--;
4383 } else /* return length of string */
4384 lpmii->cch = len;
4386 break;
4387 case MF_OWNERDRAW:
4388 case MF_BITMAP:
4389 lpmii->dwTypeData = menu->text;
4390 /* fall through */
4391 default:
4392 lpmii->cch = 0;
4396 if (lpmii->fMask & MIIM_STRING) {
4397 if(lpmii->dwTypeData && lpmii->cch) {
4398 if (unicode)
4399 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4400 lpmii->cch);
4401 else
4402 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4404 lpmii->cch = strlen(menu->text);
4407 if (lpmii->fMask & MIIM_FTYPE)
4408 lpmii->fType = menu->fType;
4410 if (lpmii->fMask & MIIM_BITMAP)
4411 lpmii->hbmpItem = menu->hbmpItem;
4413 if (lpmii->fMask & MIIM_STATE)
4414 lpmii->fState = menu->fState;
4416 if (lpmii->fMask & MIIM_ID)
4417 lpmii->wID = menu->wID;
4419 if (lpmii->fMask & MIIM_SUBMENU)
4420 lpmii->hSubMenu = menu->hSubMenu;
4422 if (lpmii->fMask & MIIM_CHECKMARKS) {
4423 lpmii->hbmpChecked = menu->hCheckBit;
4424 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4426 if (lpmii->fMask & MIIM_DATA)
4427 lpmii->dwItemData = menu->dwItemData;
4429 return TRUE;
4432 /**********************************************************************
4433 * GetMenuItemInfoA (USER32.264)
4435 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4436 LPMENUITEMINFOA lpmii)
4438 return GetMenuItemInfo_common (hmenu, item, bypos, lpmii, FALSE);
4441 /**********************************************************************
4442 * GetMenuItemInfoW (USER32.265)
4444 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4445 LPMENUITEMINFOW lpmii)
4447 return GetMenuItemInfo_common (hmenu, item, bypos,
4448 (LPMENUITEMINFOA)lpmii, TRUE);
4451 /**********************************************************************
4452 * SetMenuItemInfo_common
4455 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4456 const MENUITEMINFOA *lpmii,
4457 BOOL unicode)
4459 if (!menu) return FALSE;
4461 if (lpmii->fMask & MIIM_TYPE ) {
4462 /* Get rid of old string. */
4463 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4464 HeapFree(SystemHeap, 0, menu->text);
4465 menu->text = NULL;
4468 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4469 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4470 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4472 menu->text = lpmii->dwTypeData;
4474 if (IS_STRING_ITEM(menu->fType) && menu->text) {
4475 if (unicode)
4476 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4477 else
4478 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4482 if (lpmii->fMask & MIIM_FTYPE ) {
4483 /* free the string when the type is changing */
4484 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4485 HeapFree(SystemHeap, 0, menu->text);
4486 menu->text = NULL;
4488 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4489 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4492 if (lpmii->fMask & MIIM_STRING ) {
4493 /* free the string when used */
4494 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4495 HeapFree(SystemHeap, 0, menu->text);
4496 if (unicode)
4497 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4498 else
4499 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4503 if (lpmii->fMask & MIIM_STATE)
4505 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4506 menu->fState = lpmii->fState;
4509 if (lpmii->fMask & MIIM_ID)
4510 menu->wID = lpmii->wID;
4512 if (lpmii->fMask & MIIM_SUBMENU) {
4513 menu->hSubMenu = lpmii->hSubMenu;
4514 if (menu->hSubMenu) {
4515 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4516 if (subMenu) {
4517 subMenu->wFlags |= MF_POPUP;
4518 menu->fType |= MF_POPUP;
4520 else
4521 /* FIXME: Return an error ? */
4522 menu->fType &= ~MF_POPUP;
4524 else
4525 menu->fType &= ~MF_POPUP;
4528 if (lpmii->fMask & MIIM_CHECKMARKS)
4530 if (lpmii->fType & MFT_RADIOCHECK)
4531 menu->fType |= MFT_RADIOCHECK;
4533 menu->hCheckBit = lpmii->hbmpChecked;
4534 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4536 if (lpmii->fMask & MIIM_DATA)
4537 menu->dwItemData = lpmii->dwItemData;
4539 debug_print_menuitem("SetMenuItemInfo_common: ", menu, "");
4540 return TRUE;
4543 /**********************************************************************
4544 * SetMenuItemInfoA (USER32.491)
4546 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4547 const MENUITEMINFOA *lpmii)
4549 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4550 lpmii, FALSE);
4553 /**********************************************************************
4554 * SetMenuItemInfoW (USER32.492)
4556 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4557 const MENUITEMINFOW *lpmii)
4559 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4560 (const MENUITEMINFOA*)lpmii, TRUE);
4563 /**********************************************************************
4564 * SetMenuDefaultItem (USER32.489)
4567 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4569 UINT i;
4570 POPUPMENU *menu;
4571 MENUITEM *item;
4573 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4575 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4577 /* reset all default-item flags */
4578 item = menu->items;
4579 for (i = 0; i < menu->nItems; i++, item++)
4581 item->fState &= ~MFS_DEFAULT;
4584 /* no default item */
4585 if ( -1 == uItem)
4587 return TRUE;
4590 item = menu->items;
4591 if ( bypos )
4593 if ( uItem >= menu->nItems ) return FALSE;
4594 item[uItem].fState |= MFS_DEFAULT;
4595 return TRUE;
4597 else
4599 for (i = 0; i < menu->nItems; i++, item++)
4601 if (item->wID == uItem)
4603 item->fState |= MFS_DEFAULT;
4604 return TRUE;
4609 return FALSE;
4612 /**********************************************************************
4613 * GetMenuDefaultItem (USER32.260)
4615 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4617 POPUPMENU *menu;
4618 MENUITEM * item;
4619 UINT i = 0;
4621 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4623 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4625 /* find default item */
4626 item = menu->items;
4628 /* empty menu */
4629 if (! item) return -1;
4631 while ( !( item->fState & MFS_DEFAULT ) )
4633 i++; item++;
4634 if (i >= menu->nItems ) return -1;
4637 /* default: don't return disabled items */
4638 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4640 /* search rekursiv when needed */
4641 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4643 UINT ret;
4644 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4645 if ( -1 != ret ) return ret;
4647 /* when item not found in submenu, return the popup item */
4649 return ( bypos ) ? i : item->wID;
4653 /*******************************************************************
4654 * InsertMenuItem16 (USER.441)
4656 * FIXME: untested
4658 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4659 const MENUITEMINFO16 *mii )
4661 MENUITEMINFOA miia;
4663 miia.cbSize = sizeof(miia);
4664 miia.fMask = mii->fMask;
4665 miia.dwTypeData = mii->dwTypeData;
4666 miia.fType = mii->fType;
4667 miia.fState = mii->fState;
4668 miia.wID = mii->wID;
4669 miia.hSubMenu = mii->hSubMenu;
4670 miia.hbmpChecked = mii->hbmpChecked;
4671 miia.hbmpUnchecked = mii->hbmpUnchecked;
4672 miia.dwItemData = mii->dwItemData;
4673 miia.cch = mii->cch;
4674 if (IS_STRING_ITEM(miia.fType))
4675 miia.dwTypeData = PTR_SEG_TO_LIN(miia.dwTypeData);
4676 return InsertMenuItemA( hmenu, pos, byposition, &miia );
4680 /**********************************************************************
4681 * InsertMenuItemA (USER32.323)
4683 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4684 const MENUITEMINFOA *lpmii)
4686 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4687 return SetMenuItemInfo_common(item, lpmii, FALSE);
4691 /**********************************************************************
4692 * InsertMenuItemW (USER32.324)
4694 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4695 const MENUITEMINFOW *lpmii)
4697 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4698 return SetMenuItemInfo_common(item, (const MENUITEMINFOA*)lpmii, TRUE);
4701 /**********************************************************************
4702 * CheckMenuRadioItem (USER32.47)
4705 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4706 UINT first, UINT last, UINT check,
4707 UINT bypos)
4709 MENUITEM *mifirst, *milast, *micheck;
4710 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4712 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4713 hMenu, first, last, check, bypos);
4715 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4716 milast = MENU_FindItem (&mlast, &last, bypos);
4717 micheck = MENU_FindItem (&mcheck, &check, bypos);
4719 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4720 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4721 micheck > milast || micheck < mifirst)
4722 return FALSE;
4724 while (mifirst <= milast)
4726 if (mifirst == micheck)
4728 mifirst->fType |= MFT_RADIOCHECK;
4729 mifirst->fState |= MFS_CHECKED;
4730 } else {
4731 mifirst->fType &= ~MFT_RADIOCHECK;
4732 mifirst->fState &= ~MFS_CHECKED;
4734 mifirst++;
4737 return TRUE;
4740 /**********************************************************************
4741 * CheckMenuRadioItem16 (not a Windows API)
4744 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4745 UINT16 first, UINT16 last, UINT16 check,
4746 BOOL16 bypos)
4748 return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4751 /**********************************************************************
4752 * GetMenuItemRect (USER32.266)
4754 * ATTENTION: Here, the returned values in rect are the screen
4755 * coordinates of the item just like if the menu was
4756 * always on the upper left side of the application.
4759 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4760 LPRECT rect)
4762 POPUPMENU *itemMenu;
4763 MENUITEM *item;
4764 HWND referenceHwnd;
4766 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4768 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4769 referenceHwnd = hwnd;
4771 if(!hwnd)
4773 itemMenu = MENU_GetMenu(hMenu);
4774 if (itemMenu == NULL)
4775 return FALSE;
4777 if(itemMenu->hWnd == 0)
4778 return FALSE;
4779 referenceHwnd = itemMenu->hWnd;
4782 if ((rect == NULL) || (item == NULL))
4783 return FALSE;
4785 *rect = item->rect;
4787 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4789 return TRUE;
4792 /**********************************************************************
4793 * GetMenuItemRect16 (USER.665)
4796 BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
4797 LPRECT16 rect)
4799 RECT r32;
4800 BOOL res;
4802 if (!rect) return FALSE;
4803 res = GetMenuItemRect (hwnd, hMenu, uItem, &r32);
4804 CONV_RECT32TO16 (&r32, rect);
4805 return res;
4808 /**********************************************************************
4809 * SetMenuInfo
4811 * FIXME
4812 * MIM_APPLYTOSUBMENUS
4813 * actually use the items to draw the menu
4815 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4817 POPUPMENU *menu;
4819 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4821 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4824 if (lpmi->fMask & MIM_BACKGROUND)
4825 menu->hbrBack = lpmi->hbrBack;
4827 if (lpmi->fMask & MIM_HELPID)
4828 menu->dwContextHelpID = lpmi->dwContextHelpID;
4830 if (lpmi->fMask & MIM_MAXHEIGHT)
4831 menu->cyMax = lpmi->cyMax;
4833 if (lpmi->fMask & MIM_MENUDATA)
4834 menu->dwMenuData = lpmi->dwMenuData;
4836 if (lpmi->fMask & MIM_STYLE)
4837 menu->dwStyle = lpmi->dwStyle;
4839 return TRUE;
4841 return FALSE;
4844 /**********************************************************************
4845 * GetMenuInfo
4847 * NOTES
4848 * win98/NT5.0
4851 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4852 { POPUPMENU *menu;
4854 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4856 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4859 if (lpmi->fMask & MIM_BACKGROUND)
4860 lpmi->hbrBack = menu->hbrBack;
4862 if (lpmi->fMask & MIM_HELPID)
4863 lpmi->dwContextHelpID = menu->dwContextHelpID;
4865 if (lpmi->fMask & MIM_MAXHEIGHT)
4866 lpmi->cyMax = menu->cyMax;
4868 if (lpmi->fMask & MIM_MENUDATA)
4869 lpmi->dwMenuData = menu->dwMenuData;
4871 if (lpmi->fMask & MIM_STYLE)
4872 lpmi->dwStyle = menu->dwStyle;
4874 return TRUE;
4876 return FALSE;
4879 /**********************************************************************
4880 * SetMenuContextHelpId16 (USER.384)
4882 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4884 return SetMenuContextHelpId( hMenu, dwContextHelpID );
4888 /**********************************************************************
4889 * SetMenuContextHelpId (USER32.488)
4891 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4893 LPPOPUPMENU menu;
4895 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4897 if ((menu = MENU_GetMenu(hMenu)))
4899 menu->dwContextHelpID = dwContextHelpID;
4900 return TRUE;
4902 return FALSE;
4905 /**********************************************************************
4906 * GetMenuContextHelpId16 (USER.385)
4908 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4910 return GetMenuContextHelpId( hMenu );
4913 /**********************************************************************
4914 * GetMenuContextHelpId (USER32.488)
4916 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4918 LPPOPUPMENU menu;
4920 TRACE("(0x%04x)\n", hMenu);
4922 if ((menu = MENU_GetMenu(hMenu)))
4924 return menu->dwContextHelpID;
4926 return 0;
4929 /**********************************************************************
4930 * MenuItemFromPoint (USER32.387)
4932 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4934 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4935 hWnd, hMenu, ptScreen.x, ptScreen.y);
4936 return 0;