- moved some code from WINSPOOL_GetPrinterDriver into new function
[wine/multimedia.git] / controls / menu.c
blobf154e3d607eafe373b41cf38bac8339999db55eb
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 "wine/winestring.h"
25 #include "win.h"
26 #include "task.h"
27 #include "heap.h"
28 #include "menu.h"
29 #include "nonclient.h"
30 #include "user.h"
31 #include "message.h"
32 #include "queue.h"
33 #include "tweak.h"
35 #include "debugtools.h"
37 DEFAULT_DEBUG_CHANNEL(menu)
40 /* internal popup menu window messages */
42 #define MM_SETMENUHANDLE (WM_USER + 0)
43 #define MM_GETMENUHANDLE (WM_USER + 1)
45 /* Menu item structure */
46 typedef struct {
47 /* ----------- MENUITEMINFO Stuff ----------- */
48 UINT fType; /* Item type. */
49 UINT fState; /* Item state. */
50 UINT wID; /* Item id. */
51 HMENU hSubMenu; /* Pop-up menu. */
52 HBITMAP hCheckBit; /* Bitmap when checked. */
53 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
54 LPSTR text; /* Item text or bitmap handle. */
55 DWORD dwItemData; /* Application defined. */
56 DWORD dwTypeData; /* depends on fMask */
57 HBITMAP hbmpItem; /* bitmap in win98 style menus */
58 /* ----------- Wine stuff ----------- */
59 RECT rect; /* Item area (relative to menu window) */
60 UINT xTab; /* X position of text after Tab */
61 } MENUITEM;
63 /* Popup menu structure */
64 typedef struct {
65 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
66 WORD wMagic; /* Magic number */
67 HQUEUE16 hTaskQ; /* Task queue for this menu */
68 WORD Width; /* Width of the whole menu */
69 WORD Height; /* Height of the whole menu */
70 WORD nItems; /* Number of items in the menu */
71 HWND hWnd; /* Window containing the menu */
72 MENUITEM *items; /* Array of menu items */
73 UINT FocusedItem; /* Currently focused item */
74 HWND hwndOwner; /* window receiving the messages for ownerdraw */
75 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
76 /* ------------ MENUINFO members ------ */
77 DWORD dwStyle; /* Extended mennu style */
78 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
79 HBRUSH hbrBack; /* brush for menu background */
80 DWORD dwContextHelpID;
81 DWORD dwMenuData; /* application defined value */
82 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
83 } POPUPMENU, *LPPOPUPMENU;
85 /* internal flags for menu tracking */
87 #define TF_ENDMENU 0x0001
88 #define TF_SUSPENDPOPUP 0x0002
89 #define TF_SKIPREMOVE 0x0004
91 typedef struct
93 UINT trackFlags;
94 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
95 HMENU hTopMenu; /* initial menu */
96 HWND hOwnerWnd; /* where notifications are sent */
97 POINT pt;
98 } MTRACKER;
100 #define MENU_MAGIC 0x554d /* 'MU' */
101 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
103 #define ITEM_PREV -1
104 #define ITEM_NEXT 1
106 /* Internal MENU_TrackMenu() flags */
107 #define TPM_INTERNAL 0xF0000000
108 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
109 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
110 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
112 /* popup menu shade thickness */
113 #define POPUP_XSHADE 4
114 #define POPUP_YSHADE 4
116 /* Space between 2 menu bar items */
117 #define MENU_BAR_ITEMS_SPACE 12
119 /* Minimum width of a tab character */
120 #define MENU_TAB_SPACE 8
122 /* Height of a separator item */
123 #define SEPARATOR_HEIGHT 5
125 /* (other menu->FocusedItem values give the position of the focused item) */
126 #define NO_SELECTED_ITEM 0xffff
128 #define MENU_ITEM_TYPE(flags) \
129 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
131 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
132 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
134 #define IS_SYSTEM_MENU(menu) \
135 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
137 #define IS_SYSTEM_POPUP(menu) \
138 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
140 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
141 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
142 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
143 MF_POPUP | MF_SYSMENU | MF_HELP)
144 #define STATE_MASK (~TYPE_MASK)
146 /* Dimension of the menu bitmaps */
147 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
148 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
150 static HBITMAP hStdRadioCheck = 0;
151 static HBITMAP hStdCheck = 0;
152 static HBITMAP hStdMnArrow = 0;
154 /* Minimze/restore/close buttons to be inserted in menubar */
155 static HBITMAP hBmpMinimize = 0;
156 static HBITMAP hBmpMinimizeD = 0;
157 static HBITMAP hBmpMaximize = 0;
158 static HBITMAP hBmpMaximizeD = 0;
159 static HBITMAP hBmpClose = 0;
160 static HBITMAP hBmpCloseD = 0;
163 static HBRUSH hShadeBrush = 0;
164 static HFONT hMenuFont = 0;
165 static HFONT hMenuFontBold = 0;
167 static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
169 /* Use global popup window because there's no way 2 menus can
170 * be tracked at the same time. */
172 static WND* pTopPopupWnd = 0;
173 static UINT uSubPWndLevel = 0;
175 /* Flag set by EndMenu() to force an exit from menu tracking */
176 static BOOL fEndMenu = FALSE;
179 /***********************************************************************
180 * debug_print_menuitem
182 * Print a menuitem in readable form.
185 #define debug_print_menuitem(pre, mp, post) \
186 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
188 #define MENUOUT(text) \
189 DPRINTF("%s%s", (count++ ? "," : ""), (text))
191 #define MENUFLAG(bit,text) \
192 do { \
193 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
194 } while (0)
196 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
197 const char *postfix)
199 TRACE("%s ", prefix);
200 if (mp) {
201 UINT flags = mp->fType;
202 int typ = MENU_ITEM_TYPE(flags);
203 DPRINTF( "{ ID=0x%x", mp->wID);
204 if (flags & MF_POPUP)
205 DPRINTF( ", Sub=0x%x", mp->hSubMenu);
206 if (flags) {
207 int count = 0;
208 DPRINTF( ", Typ=");
209 if (typ == MFT_STRING)
210 /* Nothing */ ;
211 else if (typ == MFT_SEPARATOR)
212 MENUOUT("sep");
213 else if (typ == MFT_OWNERDRAW)
214 MENUOUT("own");
215 else if (typ == MFT_BITMAP)
216 MENUOUT("bit");
217 else
218 MENUOUT("???");
219 flags -= typ;
221 MENUFLAG(MF_POPUP, "pop");
222 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
223 MENUFLAG(MFT_MENUBREAK, "brk");
224 MENUFLAG(MFT_RADIOCHECK, "radio");
225 MENUFLAG(MFT_RIGHTORDER, "rorder");
226 MENUFLAG(MF_SYSMENU, "sys");
227 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
229 if (flags)
230 DPRINTF( "+0x%x", flags);
232 flags = mp->fState;
233 if (flags) {
234 int count = 0;
235 DPRINTF( ", State=");
236 MENUFLAG(MFS_GRAYED, "grey");
237 MENUFLAG(MFS_DEFAULT, "default");
238 MENUFLAG(MFS_DISABLED, "dis");
239 MENUFLAG(MFS_CHECKED, "check");
240 MENUFLAG(MFS_HILITE, "hi");
241 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
242 MENUFLAG(MF_MOUSESELECT, "mouse");
243 if (flags)
244 DPRINTF( "+0x%x", flags);
246 if (mp->hCheckBit)
247 DPRINTF( ", Chk=0x%x", mp->hCheckBit);
248 if (mp->hUnCheckBit)
249 DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
251 if (typ == MFT_STRING) {
252 if (mp->text)
253 DPRINTF( ", Text=\"%s\"", mp->text);
254 else
255 DPRINTF( ", Text=Null");
256 } else if (mp->text == NULL)
257 /* Nothing */ ;
258 else
259 DPRINTF( ", Text=%p", mp->text);
260 if (mp->dwItemData)
261 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
262 DPRINTF( " }");
263 } else {
264 DPRINTF( "NULL");
267 DPRINTF(" %s\n", postfix);
270 #undef MENUOUT
271 #undef MENUFLAG
274 /***********************************************************************
275 * MENU_GetMenu
277 * Validate the given menu handle and returns the menu structure pointer.
279 POPUPMENU *MENU_GetMenu(HMENU hMenu)
281 POPUPMENU *menu;
282 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
283 if (!IS_A_MENU(menu))
285 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
286 menu = NULL;
288 return menu;
291 /***********************************************************************
292 * MENU_CopySysPopup
294 * Return the default system menu.
296 static HMENU MENU_CopySysPopup(void)
298 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
300 if( hMenu ) {
301 POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
302 menu->wFlags |= MF_SYSMENU | MF_POPUP;
303 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
305 else {
306 hMenu = 0;
307 ERR("Unable to load default system menu\n" );
310 TRACE("returning %x.\n", hMenu );
312 return hMenu;
315 /***********************************************************************
316 * MENU_GetTopPopupWnd()
318 * Return the locked pointer pTopPopupWnd.
320 static WND *MENU_GetTopPopupWnd()
322 return WIN_LockWndPtr(pTopPopupWnd);
324 /***********************************************************************
325 * MENU_ReleaseTopPopupWnd()
327 * Realease the locked pointer pTopPopupWnd.
329 static void MENU_ReleaseTopPopupWnd()
331 WIN_ReleaseWndPtr(pTopPopupWnd);
333 /***********************************************************************
334 * MENU_DestroyTopPopupWnd()
336 * Destroy the locked pointer pTopPopupWnd.
338 static void MENU_DestroyTopPopupWnd()
340 WND *tmpWnd = pTopPopupWnd;
341 pTopPopupWnd = NULL;
342 WIN_ReleaseWndPtr(tmpWnd);
347 /**********************************************************************
348 * MENU_GetSysMenu
350 * Create a copy of the system menu. System menu in Windows is
351 * a special menu-bar with the single entry - system menu popup.
352 * This popup is presented to the outside world as a "system menu".
353 * However, the real system menu handle is sometimes seen in the
354 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
356 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
358 HMENU hMenu;
360 if ((hMenu = CreateMenu()))
362 POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
363 menu->wFlags = MF_SYSMENU;
364 menu->hWnd = hWnd;
366 if (hPopupMenu == (HMENU)(-1))
367 hPopupMenu = MENU_CopySysPopup();
368 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
370 if (hPopupMenu)
372 InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
374 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
375 menu->items[0].fState = 0;
376 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
377 menu->wFlags |= MF_SYSMENU;
379 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
380 return hMenu;
382 DestroyMenu( hMenu );
384 ERR("failed to load system menu!\n");
385 return 0;
389 /***********************************************************************
390 * MENU_Init
392 * Menus initialisation.
394 BOOL MENU_Init()
396 HBITMAP hBitmap;
397 NONCLIENTMETRICSA ncm;
399 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
400 0x55, 0, 0xAA, 0,
401 0x55, 0, 0xAA, 0,
402 0x55, 0, 0xAA, 0 };
404 /* Load menu bitmaps */
405 hStdCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK));
406 hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK));
407 hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
408 /* Load system buttons bitmaps */
409 hBmpMinimize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE));
410 hBmpMinimizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED));
411 hBmpMaximize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE));
412 hBmpMaximizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED));
413 hBmpClose = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE));
414 hBmpCloseD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED));
416 if (hStdCheck)
418 BITMAP bm;
419 GetObjectA( hStdCheck, sizeof(bm), &bm );
420 check_bitmap_width = bm.bmWidth;
421 check_bitmap_height = bm.bmHeight;
422 } else
423 return FALSE;
425 /* Assume that radio checks have the same size as regular check. */
426 if (!hStdRadioCheck)
427 return FALSE;
429 if (hStdMnArrow)
431 BITMAP bm;
432 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
433 arrow_bitmap_width = bm.bmWidth;
434 arrow_bitmap_height = bm.bmHeight;
435 } else
436 return FALSE;
438 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
439 return FALSE;
441 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
442 return FALSE;
444 DeleteObject( hBitmap );
445 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
446 return FALSE;
448 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
449 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
450 return FALSE;
452 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
453 return FALSE;
455 ncm.lfMenuFont.lfWeight += 300;
456 if ( ncm.lfMenuFont.lfWeight > 1000)
457 ncm.lfMenuFont.lfWeight = 1000;
459 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
460 return FALSE;
462 return TRUE;
465 /***********************************************************************
466 * MENU_InitSysMenuPopup
468 * Grey the appropriate items in System menu.
470 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
472 BOOL gray;
474 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
475 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
476 gray = ((style & WS_MAXIMIZE) != 0);
477 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
478 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
479 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
480 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
481 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
482 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
483 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
484 gray = (clsStyle & CS_NOCLOSE) != 0;
486 /* The menu item must keep its state if it's disabled */
487 if(gray)
488 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
492 /******************************************************************************
494 * UINT MENU_GetStartOfNextColumn(
495 * HMENU hMenu )
497 *****************************************************************************/
499 static UINT MENU_GetStartOfNextColumn(
500 HMENU hMenu )
502 POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
503 UINT i = menu->FocusedItem + 1;
505 if(!menu)
506 return NO_SELECTED_ITEM;
508 if( i == NO_SELECTED_ITEM )
509 return i;
511 for( ; i < menu->nItems; ++i ) {
512 if (menu->items[i].fType & MF_MENUBARBREAK)
513 return i;
516 return NO_SELECTED_ITEM;
520 /******************************************************************************
522 * UINT MENU_GetStartOfPrevColumn(
523 * HMENU hMenu )
525 *****************************************************************************/
527 static UINT MENU_GetStartOfPrevColumn(
528 HMENU hMenu )
530 POPUPMENU const *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
531 UINT i;
533 if( !menu )
534 return NO_SELECTED_ITEM;
536 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
537 return NO_SELECTED_ITEM;
539 /* Find the start of the column */
541 for(i = menu->FocusedItem; i != 0 &&
542 !(menu->items[i].fType & MF_MENUBARBREAK);
543 --i); /* empty */
545 if(i == 0)
546 return NO_SELECTED_ITEM;
548 for(--i; i != 0; --i) {
549 if (menu->items[i].fType & MF_MENUBARBREAK)
550 break;
553 TRACE("ret %d.\n", i );
555 return i;
560 /***********************************************************************
561 * MENU_FindItem
563 * Find a menu item. Return a pointer on the item, and modifies *hmenu
564 * in case the item was in a sub-menu.
566 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
568 POPUPMENU *menu;
569 UINT i;
571 if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
572 if (wFlags & MF_BYPOSITION)
574 if (*nPos >= menu->nItems) return NULL;
575 return &menu->items[*nPos];
577 else
579 MENUITEM *item = menu->items;
580 for (i = 0; i < menu->nItems; i++, item++)
582 if (item->wID == *nPos)
584 *nPos = i;
585 return item;
587 else if (item->fType & MF_POPUP)
589 HMENU hsubmenu = item->hSubMenu;
590 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
591 if (subitem)
593 *hmenu = hsubmenu;
594 return subitem;
599 return NULL;
602 /***********************************************************************
603 * MENU_FindSubMenu
605 * Find a Sub menu. Return the position of the submenu, and modifies
606 * *hmenu in case it is found in another sub-menu.
607 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
609 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
611 POPUPMENU *menu;
612 UINT i;
613 MENUITEM *item;
614 if (((*hmenu)==0xffff) ||
615 (!(menu = MENU_GetMenu(*hmenu))))
616 return NO_SELECTED_ITEM;
617 item = menu->items;
618 for (i = 0; i < menu->nItems; i++, item++) {
619 if(!(item->fType & MF_POPUP)) continue;
620 if (item->hSubMenu == hSubTarget) {
621 return i;
623 else {
624 HMENU hsubmenu = item->hSubMenu;
625 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
626 if (pos != NO_SELECTED_ITEM) {
627 *hmenu = hsubmenu;
628 return pos;
632 return NO_SELECTED_ITEM;
635 /***********************************************************************
636 * MENU_FreeItemData
638 static void MENU_FreeItemData( MENUITEM* item )
640 /* delete text */
641 if (IS_STRING_ITEM(item->fType) && item->text)
642 HeapFree( SystemHeap, 0, item->text );
645 /***********************************************************************
646 * MENU_FindItemByCoords
648 * Find the item at the specified coordinates (screen coords). Does
649 * not work for child windows and therefore should not be called for
650 * an arbitrary system menu.
652 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
653 POINT pt, UINT *pos )
655 MENUITEM *item;
656 UINT i;
657 RECT wrect;
659 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
660 pt.x -= wrect.left;pt.y -= wrect.top;
661 item = menu->items;
662 for (i = 0; i < menu->nItems; i++, item++)
664 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
665 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
667 if (pos) *pos = i;
668 return item;
671 return NULL;
675 /***********************************************************************
676 * MENU_FindItemByKey
678 * Find the menu item selected by a key press.
679 * Return item id, -1 if none, -2 if we should close the menu.
681 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
682 UINT key, BOOL forceMenuChar )
684 TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
686 if (!IsMenu( hmenu ))
688 WND* w = WIN_FindWndPtr(hwndOwner);
689 hmenu = GetSubMenu(w->hSysMenu, 0);
690 WIN_ReleaseWndPtr(w);
693 if (hmenu)
695 POPUPMENU *menu = MENU_GetMenu( hmenu );
696 MENUITEM *item = menu->items;
697 LONG menuchar;
699 if( !forceMenuChar )
701 UINT i;
703 key = toupper(key);
704 for (i = 0; i < menu->nItems; i++, item++)
706 if (item->text && (IS_STRING_ITEM(item->fType)))
708 char *p = item->text - 2;
711 p = strchr (p + 2, '&');
713 while (p != NULL && p [1] == '&');
714 if (p && (toupper(p[1]) == key)) return i;
718 menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
719 MAKEWPARAM( key, menu->wFlags ), hmenu );
720 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
721 if (HIWORD(menuchar) == 1) return (UINT)(-2);
723 return (UINT)(-1);
725 /***********************************************************************
726 * MENU_LoadMagicItem
728 * Load the bitmap associated with the magic menu item and its style
731 static HBITMAP MENU_LoadMagicItem(UINT id, BOOL hilite, DWORD dwItemData)
734 * Magic menu item id's section
735 * These magic id's are used by windows to insert "standard" mdi
736 * buttons (minimize,restore,close) on menu. Under windows,
737 * these magic id's make sure the right things appear when those
738 * bitmap buttons are pressed/selected/released.
741 switch(id & 0xffff)
742 { case HBMMENU_SYSTEM:
743 return (dwItemData) ?
744 (HBITMAP)dwItemData :
745 (hilite ? hBmpMinimizeD : hBmpMinimize);
746 case HBMMENU_MBAR_RESTORE:
747 return (hilite ? hBmpMaximizeD: hBmpMaximize);
748 case HBMMENU_MBAR_MINIMIZE:
749 return (hilite ? hBmpMinimizeD : hBmpMinimize);
750 case HBMMENU_MBAR_CLOSE:
751 return (hilite ? hBmpCloseD : hBmpClose);
752 case HBMMENU_CALLBACK:
753 case HBMMENU_MBAR_CLOSE_D:
754 case HBMMENU_MBAR_MINIMIZE_D:
755 case HBMMENU_POPUP_CLOSE:
756 case HBMMENU_POPUP_RESTORE:
757 case HBMMENU_POPUP_MAXIMIZE:
758 case HBMMENU_POPUP_MINIMIZE:
759 default:
760 FIXME("Magic 0x%08x not implemented\n", id);
761 return 0;
766 /***********************************************************************
767 * MENU_CalcItemSize
769 * Calculate the size of the menu item and store it in lpitem->rect.
771 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
772 INT orgX, INT orgY, BOOL menuBar )
774 char *p;
776 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
777 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
778 (menuBar ? " (MenuBar)" : ""));
780 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
782 if (lpitem->fType & MF_OWNERDRAW)
785 ** Experimentation under Windows reveals that an owner-drawn
786 ** menu is expected to return the size of the content part of
787 ** the menu item, not including the checkmark nor the submenu
788 ** arrow. Windows adds those values itself and returns the
789 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
791 MEASUREITEMSTRUCT mis;
792 mis.CtlType = ODT_MENU;
793 mis.CtlID = 0;
794 mis.itemID = lpitem->wID;
795 mis.itemData = (DWORD)lpitem->dwItemData;
796 mis.itemHeight = 0;
797 mis.itemWidth = 0;
798 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
799 lpitem->rect.right += mis.itemWidth;
801 if (menuBar)
803 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
806 /* under at least win95 you seem to be given a standard
807 height for the menu and the height value is ignored */
809 if (TWEAK_WineLook == WIN31_LOOK)
810 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
811 else
812 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
814 else
815 lpitem->rect.bottom += mis.itemHeight;
817 TRACE("id=%04x size=%dx%d\n",
818 lpitem->wID, mis.itemWidth, mis.itemHeight);
819 /* Fall through to get check/arrow width calculation. */
822 if (lpitem->fType & MF_SEPARATOR)
824 lpitem->rect.bottom += SEPARATOR_HEIGHT;
825 return;
828 if (!menuBar)
830 lpitem->rect.right += 2 * check_bitmap_width;
831 if (lpitem->fType & MF_POPUP)
832 lpitem->rect.right += arrow_bitmap_width;
835 if (lpitem->fType & MF_OWNERDRAW)
836 return;
838 if (IS_BITMAP_ITEM(lpitem->fType))
840 BITMAP bm;
841 HBITMAP resBmp = 0;
843 /* Check if there is a magic menu item associated with this item */
844 if((LOWORD((int)lpitem->text))<12)
846 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fType & MF_HILITE),
847 lpitem->dwItemData);
849 else
850 resBmp = (HBITMAP)lpitem->text;
852 if (GetObjectA(resBmp, sizeof(bm), &bm ))
854 lpitem->rect.right += bm.bmWidth;
855 lpitem->rect.bottom += bm.bmHeight;
861 /* If we get here, then it must be a text item */
862 if (IS_STRING_ITEM( lpitem->fType ))
863 { SIZE size;
865 GetTextExtentPoint32A(hdc, lpitem->text, strlen(lpitem->text), &size);
867 lpitem->rect.right += size.cx;
868 if (TWEAK_WineLook == WIN31_LOOK)
869 lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
870 else
871 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
872 lpitem->xTab = 0;
874 if (menuBar)
876 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
878 else if ((p = strchr( lpitem->text, '\t' )) != NULL)
880 /* Item contains a tab (only meaningful in popup menus) */
881 GetTextExtentPoint32A(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
882 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
883 lpitem->rect.right += MENU_TAB_SPACE;
885 else
887 if (strchr( lpitem->text, '\b' ))
888 lpitem->rect.right += MENU_TAB_SPACE;
889 lpitem->xTab = lpitem->rect.right - check_bitmap_width
890 - arrow_bitmap_width;
893 TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
897 /***********************************************************************
898 * MENU_PopupMenuCalcSize
900 * Calculate the size of a popup menu.
902 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
904 MENUITEM *lpitem;
905 HDC hdc;
906 int start, i;
907 int orgX, orgY, maxX, maxTab, maxTabWidth;
909 lppop->Width = lppop->Height = 0;
910 if (lppop->nItems == 0) return;
911 hdc = GetDC( 0 );
913 SelectObject( hdc, hMenuFont);
915 start = 0;
916 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2 ;
918 while (start < lppop->nItems)
920 lpitem = &lppop->items[start];
921 orgX = maxX;
922 orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
924 maxTab = maxTabWidth = 0;
926 /* Parse items until column break or end of menu */
927 for (i = start; i < lppop->nItems; i++, lpitem++)
929 if ((i != start) &&
930 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
932 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
934 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
935 maxX = max( maxX, lpitem->rect.right );
936 orgY = lpitem->rect.bottom;
937 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
939 maxTab = max( maxTab, lpitem->xTab );
940 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
944 /* Finish the column (set all items to the largest width found) */
945 maxX = max( maxX, maxTab + maxTabWidth );
946 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
948 lpitem->rect.right = maxX;
949 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
950 lpitem->xTab = maxTab;
953 lppop->Height = max( lppop->Height, orgY );
956 lppop->Width = maxX;
958 /* space for 3d border */
959 if(TWEAK_WineLook > WIN31_LOOK)
961 lppop->Height += 2;
962 lppop->Width += 2;
965 ReleaseDC( 0, hdc );
969 /***********************************************************************
970 * MENU_MenuBarCalcSize
972 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
973 * height is off by 1 pixel which causes lengthy window relocations when
974 * active document window is maximized/restored.
976 * Calculate the size of the menu bar.
978 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
979 LPPOPUPMENU lppop, HWND hwndOwner )
981 MENUITEM *lpitem;
982 int start, i, orgX, orgY, maxY, helpPos;
984 if ((lprect == NULL) || (lppop == NULL)) return;
985 if (lppop->nItems == 0) return;
986 TRACE("left=%d top=%d right=%d bottom=%d\n",
987 lprect->left, lprect->top, lprect->right, lprect->bottom);
988 lppop->Width = lprect->right - lprect->left;
989 lppop->Height = 0;
990 maxY = lprect->top;
991 start = 0;
992 helpPos = -1;
993 while (start < lppop->nItems)
995 lpitem = &lppop->items[start];
996 orgX = lprect->left;
997 orgY = maxY;
999 /* Parse items until line break or end of menu */
1000 for (i = start; i < lppop->nItems; i++, lpitem++)
1002 if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i;
1003 if ((i != start) &&
1004 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1006 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1007 orgX, orgY );
1008 debug_print_menuitem (" item: ", lpitem, "");
1009 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1011 if (lpitem->rect.right > lprect->right)
1013 if (i != start) break;
1014 else lpitem->rect.right = lprect->right;
1016 maxY = max( maxY, lpitem->rect.bottom );
1017 orgX = lpitem->rect.right;
1020 /* Finish the line (set all items to the largest height found) */
1021 while (start < i) lppop->items[start++].rect.bottom = maxY;
1024 lprect->bottom = maxY;
1025 lppop->Height = lprect->bottom - lprect->top;
1027 /* Flush right all magic items and items between the MF_HELP and */
1028 /* the last item (if several lines, only move the last line) */
1029 lpitem = &lppop->items[lppop->nItems-1];
1030 orgY = lpitem->rect.top;
1031 orgX = lprect->right;
1032 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
1034 if ( !IS_BITMAP_ITEM(lpitem->fType) && ((helpPos ==-1) ? TRUE : (helpPos>i) ))
1035 break; /* done */
1036 if (lpitem->rect.top != orgY) break; /* Other line */
1037 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1038 lpitem->rect.left += orgX - lpitem->rect.right;
1039 lpitem->rect.right = orgX;
1040 orgX = lpitem->rect.left;
1044 /***********************************************************************
1045 * MENU_DrawMenuItem
1047 * Draw a single menu item.
1049 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1050 UINT height, BOOL menuBar, UINT odaction )
1052 RECT rect;
1054 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1056 if (lpitem->fType & MF_SYSMENU)
1058 if( !IsIconic(hwnd) ) {
1059 if (TWEAK_WineLook > WIN31_LOOK)
1060 NC_DrawSysButton95( hwnd, hdc,
1061 lpitem->fState &
1062 (MF_HILITE | MF_MOUSESELECT) );
1063 else
1064 NC_DrawSysButton( hwnd, hdc,
1065 lpitem->fState &
1066 (MF_HILITE | MF_MOUSESELECT) );
1069 return;
1072 if (lpitem->fType & MF_OWNERDRAW)
1075 ** Experimentation under Windows reveals that an owner-drawn
1076 ** menu is given the rectangle which includes the space it requested
1077 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1078 ** and a popup-menu arrow. This is the value of lpitem->rect.
1079 ** Windows will leave all drawing to the application except for
1080 ** the popup-menu arrow. Windows always draws that itself, after
1081 ** the menu owner has finished drawing.
1083 DRAWITEMSTRUCT dis;
1085 dis.CtlType = ODT_MENU;
1086 dis.CtlID = 0;
1087 dis.itemID = lpitem->wID;
1088 dis.itemData = (DWORD)lpitem->dwItemData;
1089 dis.itemState = 0;
1090 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1091 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED;
1092 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1093 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1094 dis.hwndItem = hmenu;
1095 dis.hDC = hdc;
1096 dis.rcItem = lpitem->rect;
1097 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1098 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
1099 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1100 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1101 dis.rcItem.bottom);
1102 SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1103 /* Fall through to draw popup-menu arrow */
1106 TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
1107 lpitem->rect.right,lpitem->rect.bottom);
1109 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1111 rect = lpitem->rect;
1113 if (!(lpitem->fType & MF_OWNERDRAW))
1115 if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)))
1116 if ((menuBar) && (TWEAK_WineLook==WIN98_LOOK))
1117 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1118 else
1119 FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
1120 else
1121 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1124 SetBkMode( hdc, TRANSPARENT );
1126 if (!(lpitem->fType & MF_OWNERDRAW))
1128 /* vertical separator */
1129 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1131 if (TWEAK_WineLook > WIN31_LOOK)
1133 RECT rc = rect;
1134 rc.top = 3;
1135 rc.bottom = height - 3;
1136 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1138 else
1140 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1141 MoveToEx( hdc, rect.left, 0, NULL );
1142 LineTo( hdc, rect.left, height );
1146 /* horizontal separator */
1147 if (lpitem->fType & MF_SEPARATOR)
1149 if (TWEAK_WineLook > WIN31_LOOK)
1151 RECT rc = rect;
1152 rc.left++;
1153 rc.right--;
1154 rc.top += SEPARATOR_HEIGHT / 2;
1155 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1157 else
1159 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1160 MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
1161 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1163 return;
1167 /* Setup colors */
1169 if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)) )
1171 if (lpitem->fState & MF_GRAYED)
1172 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1173 else
1174 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
1175 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
1177 else
1179 if (lpitem->fState & MF_GRAYED)
1180 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1181 else
1182 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1183 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1186 /* helper lines for debugging */
1187 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1188 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1189 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1190 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1193 if (!menuBar)
1195 INT y = rect.top + rect.bottom;
1197 if (!(lpitem->fType & MF_OWNERDRAW))
1199 /* Draw the check mark
1201 * FIXME:
1202 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1205 if (lpitem->fState & MF_CHECKED)
1207 HBITMAP bm = lpitem->hCheckBit ? lpitem->hCheckBit :
1208 ((lpitem->fType & MFT_RADIOCHECK) ? hStdRadioCheck : hStdCheck);
1209 HDC hdcMem = CreateCompatibleDC( hdc );
1211 SelectObject( hdcMem, bm );
1212 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1213 check_bitmap_width, check_bitmap_height,
1214 hdcMem, 0, 0, SRCCOPY );
1215 DeleteDC( hdcMem );
1217 else if (lpitem->hUnCheckBit)
1219 HDC hdcMem = CreateCompatibleDC( hdc );
1221 SelectObject( hdcMem, lpitem->hUnCheckBit );
1222 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1223 check_bitmap_width, check_bitmap_height,
1224 hdcMem, 0, 0, SRCCOPY );
1225 DeleteDC( hdcMem );
1229 /* Draw the popup-menu arrow */
1230 if (lpitem->fType & MF_POPUP)
1232 HDC hdcMem = CreateCompatibleDC( hdc );
1233 HBITMAP hOrigBitmap;
1235 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1236 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1237 (y - arrow_bitmap_height) / 2,
1238 arrow_bitmap_width, arrow_bitmap_height,
1239 hdcMem, 0, 0, SRCCOPY );
1240 SelectObject( hdcMem, hOrigBitmap );
1241 DeleteDC( hdcMem );
1244 rect.left += check_bitmap_width;
1245 rect.right -= arrow_bitmap_width;
1248 /* Done for owner-drawn */
1249 if (lpitem->fType & MF_OWNERDRAW)
1250 return;
1252 /* Draw the item text or bitmap */
1253 if (IS_BITMAP_ITEM(lpitem->fType))
1254 { int top;
1256 HBITMAP resBmp = 0;
1258 HDC hdcMem = CreateCompatibleDC( hdc );
1261 * Check if there is a magic menu item associated with this item
1262 * and load the appropriate bitmap
1264 if((LOWORD((int)lpitem->text)) < 12)
1266 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fState & MF_HILITE),
1267 lpitem->dwItemData);
1269 else
1270 resBmp = (HBITMAP)lpitem->text;
1272 if (resBmp)
1274 BITMAP bm;
1275 GetObjectA( resBmp, sizeof(bm), &bm );
1277 SelectObject(hdcMem,resBmp );
1279 /* handle fontsize > bitmap_height */
1280 top = ((rect.bottom-rect.top)>bm.bmHeight) ?
1281 rect.top+(rect.bottom-rect.top-bm.bmHeight)/2 : rect.top;
1283 BitBlt( hdc, rect.left, top, rect.right - rect.left,
1284 rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY );
1286 DeleteDC( hdcMem );
1288 return;
1291 /* No bitmap - process text if present */
1292 else if (IS_STRING_ITEM(lpitem->fType))
1294 register int i;
1295 HFONT hfontOld = 0;
1297 UINT uFormat = (menuBar) ?
1298 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1299 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1301 if ( lpitem->fState & MFS_DEFAULT )
1303 hfontOld = SelectObject( hdc, hMenuFontBold);
1306 if (menuBar)
1308 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1309 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1310 i = strlen( lpitem->text );
1312 else
1314 for (i = 0; lpitem->text[i]; i++)
1315 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1316 break;
1319 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1321 if (!(lpitem->fState & MF_HILITE) )
1323 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1324 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1325 DrawTextA( hdc, lpitem->text, i, &rect, uFormat );
1326 --rect.left; --rect.top; --rect.right; --rect.bottom;
1328 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1331 DrawTextA( hdc, lpitem->text, i, &rect, uFormat);
1333 /* paint the shortcut text */
1334 if (lpitem->text[i]) /* There's a tab or flush-right char */
1336 if (lpitem->text[i] == '\t')
1338 rect.left = lpitem->xTab;
1339 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1341 else
1343 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1346 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1348 if (!(lpitem->fState & MF_HILITE) )
1350 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1351 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1352 DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1353 --rect.left; --rect.top; --rect.right; --rect.bottom;
1355 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1357 DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1360 if (hfontOld)
1361 SelectObject (hdc, hfontOld);
1366 /***********************************************************************
1367 * MENU_DrawPopupMenu
1369 * Paint a popup menu.
1371 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1373 HBRUSH hPrevBrush = 0;
1374 RECT rect;
1376 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1378 GetClientRect( hwnd, &rect );
1380 if(TWEAK_WineLook == WIN31_LOOK)
1382 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1383 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1386 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1387 && (SelectObject( hdc, hMenuFont)))
1389 HPEN hPrevPen;
1391 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1393 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1394 if( hPrevPen )
1396 INT ropPrev, i;
1397 POPUPMENU *menu;
1399 /* draw 3-d shade */
1400 if(TWEAK_WineLook == WIN31_LOOK) {
1401 SelectObject( hdc, hShadeBrush );
1402 SetBkMode( hdc, TRANSPARENT );
1403 ropPrev = SetROP2( hdc, R2_MASKPEN );
1405 i = rect.right; /* why SetBrushOrg() doesn't? */
1406 PatBlt( hdc, i & 0xfffffffe,
1407 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1408 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1409 rect.bottom - rect.top, 0x00a000c9 );
1410 i = rect.bottom;
1411 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1412 i & 0xfffffffe,rect.right - rect.left,
1413 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1414 SelectObject( hdc, hPrevPen );
1415 SelectObject( hdc, hPrevBrush );
1416 SetROP2( hdc, ropPrev );
1418 else
1419 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1421 /* draw menu items */
1423 menu = MENU_GetMenu( hmenu );
1424 if (menu && menu->nItems)
1426 MENUITEM *item;
1427 UINT u;
1429 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1430 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1431 menu->Height, FALSE, ODA_DRAWENTIRE );
1434 } else
1436 SelectObject( hdc, hPrevBrush );
1441 /***********************************************************************
1442 * MENU_DrawMenuBar
1444 * Paint a menu bar. Returns the height of the menu bar.
1445 * called from [windows/nonclient.c]
1447 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1448 BOOL suppress_draw)
1450 LPPOPUPMENU lppop;
1451 UINT i,retvalue;
1452 HFONT hfontOld = 0;
1454 WND *wndPtr = WIN_FindWndPtr( hwnd );
1456 lppop = MENU_GetMenu ((HMENU)wndPtr->wIDmenu );
1457 if (lppop == NULL || lprect == NULL)
1459 retvalue = GetSystemMetrics(SM_CYMENU);
1460 goto END;
1463 TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1465 hfontOld = SelectObject( hDC, hMenuFont);
1467 if (lppop->Height == 0)
1468 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1470 lprect->bottom = lprect->top + lppop->Height;
1472 if (suppress_draw)
1474 retvalue = lppop->Height;
1475 goto END;
1478 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1480 if (TWEAK_WineLook == WIN31_LOOK)
1482 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1483 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1484 LineTo( hDC, lprect->right, lprect->bottom );
1486 else
1488 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1489 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1490 LineTo( hDC, lprect->right, lprect->bottom );
1493 if (lppop->nItems == 0)
1495 retvalue = GetSystemMetrics(SM_CYMENU);
1496 goto END;
1499 for (i = 0; i < lppop->nItems; i++)
1501 MENU_DrawMenuItem( hwnd, (HMENU)wndPtr->wIDmenu, hwnd,
1502 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
1504 retvalue = lppop->Height;
1506 END:
1507 if (hfontOld)
1508 SelectObject (hDC, hfontOld);
1510 WIN_ReleaseWndPtr(wndPtr);
1511 return retvalue;
1514 /***********************************************************************
1515 * MENU_PatchResidentPopup
1517 BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
1519 WND *pTPWnd = MENU_GetTopPopupWnd();
1521 if( pTPWnd )
1523 HTASK16 hTask = 0;
1525 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1526 checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTPWnd->hmemTaskQ,
1527 pTPWnd->owner ? pTPWnd->owner->hwndSelf : 0);
1529 switch( checkQueue )
1531 case 0: /* checkWnd is the new popup owner */
1532 if( checkWnd )
1534 pTPWnd->owner = checkWnd;
1535 if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
1536 hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
1538 break;
1540 case 0xFFFF: /* checkWnd is destroyed */
1541 if( pTPWnd->owner == checkWnd )
1542 pTPWnd->owner = NULL;
1543 MENU_ReleaseTopPopupWnd();
1544 return TRUE;
1546 default: /* checkQueue is exiting */
1547 if( pTPWnd->hmemTaskQ == checkQueue )
1549 hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
1550 hTask = TASK_GetNextTask( hTask );
1552 break;
1555 if( hTask )
1557 TDB* task = (TDB*)GlobalLock16( hTask );
1558 if( task )
1560 pTPWnd->hInstance = task->hInstance;
1561 pTPWnd->hmemTaskQ = task->hQueue;
1562 MENU_ReleaseTopPopupWnd();
1563 return TRUE;
1565 else WARN("failed to patch resident popup.\n");
1568 MENU_ReleaseTopPopupWnd();
1569 return FALSE;
1572 /***********************************************************************
1573 * MENU_ShowPopup
1575 * Display a popup menu.
1577 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1578 INT x, INT y, INT xanchor, INT yanchor )
1580 POPUPMENU *menu;
1581 WND *wndOwner = NULL;
1583 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1584 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1586 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1587 if (menu->FocusedItem != NO_SELECTED_ITEM)
1589 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1590 menu->FocusedItem = NO_SELECTED_ITEM;
1593 /* store the owner for DrawItem*/
1594 menu->hwndOwner = hwndOwner;
1596 if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
1598 UINT width, height;
1600 MENU_PopupMenuCalcSize( menu, hwndOwner );
1602 /* adjust popup menu pos so that it fits within the desktop */
1604 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1605 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1607 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1609 if( xanchor )
1610 x -= width - xanchor;
1611 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1612 x = GetSystemMetrics(SM_CXSCREEN) - width;
1614 if( x < 0 ) x = 0;
1616 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1618 if( yanchor )
1619 y -= height + yanchor;
1620 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1621 y = GetSystemMetrics(SM_CYSCREEN) - height;
1623 if( y < 0 ) y = 0;
1625 if( TWEAK_WineLook == WIN31_LOOK )
1627 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1628 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1631 /* NOTE: In Windows, top menu popup is not owned. */
1632 if (!pTopPopupWnd) /* create top level popup menu window */
1634 assert( uSubPWndLevel == 0 );
1636 pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1637 WS_POPUP, x, y, width, height,
1638 hwndOwner, 0, wndOwner->hInstance,
1639 (LPVOID)hmenu ));
1640 if (!pTopPopupWnd)
1642 WIN_ReleaseWndPtr(wndOwner);
1643 return FALSE;
1645 menu->hWnd = pTopPopupWnd->hwndSelf;
1646 MENU_ReleaseTopPopupWnd();
1648 else
1649 if( uSubPWndLevel )
1651 /* create a new window for the submenu */
1653 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1654 WS_POPUP, x, y, width, height,
1655 hwndOwner, 0, wndOwner->hInstance,
1656 (LPVOID)hmenu );
1657 if( !menu->hWnd )
1659 WIN_ReleaseWndPtr(wndOwner);
1660 return FALSE;
1663 else /* top level popup menu window already exists */
1665 WND *pTPWnd = MENU_GetTopPopupWnd();
1666 menu->hWnd = pTPWnd->hwndSelf;
1668 MENU_PatchResidentPopup( 0, wndOwner );
1669 SendMessageA( pTPWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);
1671 /* adjust its size */
1673 SetWindowPos( menu->hWnd, 0, x, y, width, height,
1674 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
1675 MENU_ReleaseTopPopupWnd();
1678 uSubPWndLevel++; /* menu level counter */
1680 /* Display the window */
1682 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1683 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1684 UpdateWindow( menu->hWnd );
1685 WIN_ReleaseWndPtr(wndOwner);
1686 return TRUE;
1688 return FALSE;
1692 /***********************************************************************
1693 * MENU_SelectItem
1695 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1696 BOOL sendMenuSelect, HMENU topmenu )
1698 LPPOPUPMENU lppop;
1699 HDC hdc;
1701 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1703 lppop = MENU_GetMenu( hmenu );
1704 if ((!lppop) || (!lppop->nItems)) return;
1706 if (lppop->FocusedItem == wIndex) return;
1707 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1708 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1710 SelectObject( hdc, hMenuFont);
1712 /* Clear previous highlighted item */
1713 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1715 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1716 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1717 lppop->Height, !(lppop->wFlags & MF_POPUP),
1718 ODA_SELECT );
1721 /* Highlight new item (if any) */
1722 lppop->FocusedItem = wIndex;
1723 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1725 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1726 lppop->items[wIndex].fState |= MF_HILITE;
1727 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1728 &lppop->items[wIndex], lppop->Height,
1729 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1731 if (sendMenuSelect)
1733 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1734 SendMessageA( hwndOwner, WM_MENUSELECT,
1735 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1736 ip->fType | ip->fState | MF_MOUSESELECT |
1737 (lppop->wFlags & MF_SYSMENU)), hmenu);
1740 else if (sendMenuSelect) {
1741 if(topmenu){
1742 int pos;
1743 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1744 POPUPMENU *ptm = (POPUPMENU *) USER_HEAP_LIN_ADDR( topmenu );
1745 MENUITEM *ip = &ptm->items[pos];
1746 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1747 ip->fType | ip->fState | MF_MOUSESELECT |
1748 (ptm->wFlags & MF_SYSMENU)), topmenu);
1752 ReleaseDC( lppop->hWnd, hdc );
1756 /***********************************************************************
1757 * MENU_MoveSelection
1759 * Moves currently selected item according to the offset parameter.
1760 * If there is no selection then it should select the last item if
1761 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1763 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1765 INT i;
1766 POPUPMENU *menu;
1768 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1770 menu = MENU_GetMenu( hmenu );
1771 if ((!menu) || (!menu->items)) return;
1773 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1775 if( menu->nItems == 1 ) return; else
1776 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1777 ; i += offset)
1778 if (!(menu->items[i].fType & MF_SEPARATOR))
1780 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1781 return;
1785 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1786 i >= 0 && i < menu->nItems ; i += offset)
1787 if (!(menu->items[i].fType & MF_SEPARATOR))
1789 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1790 return;
1795 /**********************************************************************
1796 * MENU_SetItemData
1798 * Set an item flags, id and text ptr. Called by InsertMenu() and
1799 * ModifyMenu().
1801 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1802 LPCSTR str )
1804 LPSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1806 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1808 if (IS_STRING_ITEM(flags))
1810 if (!str || !*str)
1812 flags |= MF_SEPARATOR;
1813 item->text = NULL;
1815 else
1817 LPSTR text;
1818 /* Item beginning with a backspace is a help item */
1819 if (*str == '\b')
1821 flags |= MF_HELP;
1822 str++;
1824 if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1825 item->text = text;
1828 else if (IS_BITMAP_ITEM(flags))
1829 item->text = (LPSTR)(HBITMAP)LOWORD(str);
1830 else item->text = NULL;
1832 if (flags & MF_OWNERDRAW)
1833 item->dwItemData = (DWORD)str;
1834 else
1835 item->dwItemData = 0;
1837 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1838 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1840 if (flags & MF_POPUP)
1842 POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1843 if (menu) menu->wFlags |= MF_POPUP;
1844 else
1846 item->wID = 0;
1847 item->hSubMenu = 0;
1848 item->fType = 0;
1849 item->fState = 0;
1850 return FALSE;
1854 item->wID = id;
1855 if (flags & MF_POPUP)
1856 item->hSubMenu = id;
1858 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1859 flags |= MF_POPUP; /* keep popup */
1861 item->fType = flags & TYPE_MASK;
1862 item->fState = (flags & STATE_MASK) &
1863 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1866 /* Don't call SetRectEmpty here! */
1869 if (prevText) HeapFree( SystemHeap, 0, prevText );
1871 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1872 return TRUE;
1876 /**********************************************************************
1877 * MENU_InsertItem
1879 * Insert a new item into a menu.
1881 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1883 MENUITEM *newItems;
1884 POPUPMENU *menu;
1886 if (!(menu = MENU_GetMenu(hMenu)))
1887 return NULL;
1889 /* Find where to insert new item */
1891 if (flags & MF_BYPOSITION) {
1892 if (pos > menu->nItems)
1893 pos = menu->nItems;
1894 } else {
1895 if (!MENU_FindItem( &hMenu, &pos, flags ))
1896 pos = menu->nItems;
1897 else {
1898 if (!(menu = MENU_GetMenu( hMenu )))
1899 return NULL;
1903 /* Create new items array */
1905 newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1906 if (!newItems)
1908 WARN("allocation failed\n" );
1909 return NULL;
1911 if (menu->nItems > 0)
1913 /* Copy the old array into the new */
1914 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1915 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1916 (menu->nItems-pos)*sizeof(MENUITEM) );
1917 HeapFree( SystemHeap, 0, menu->items );
1919 menu->items = newItems;
1920 menu->nItems++;
1921 memset( &newItems[pos], 0, sizeof(*newItems) );
1922 menu->Height = 0; /* force size recalculate */
1923 return &newItems[pos];
1927 /**********************************************************************
1928 * MENU_ParseResource
1930 * Parse a standard menu resource and add items to the menu.
1931 * Return a pointer to the end of the resource.
1933 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1935 WORD flags, id = 0;
1936 LPCSTR str;
1940 flags = GET_WORD(res);
1941 res += sizeof(WORD);
1942 if (!(flags & MF_POPUP))
1944 id = GET_WORD(res);
1945 res += sizeof(WORD);
1947 if (!IS_STRING_ITEM(flags))
1948 ERR("not a string item %04x\n", flags );
1949 str = res;
1950 if (!unicode) res += strlen(str) + 1;
1951 else res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1952 if (flags & MF_POPUP)
1954 HMENU hSubMenu = CreatePopupMenu();
1955 if (!hSubMenu) return NULL;
1956 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1957 return NULL;
1958 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1959 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1961 else /* Not a popup */
1963 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1964 else AppendMenuW( hMenu, flags, id,
1965 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1967 } while (!(flags & MF_END));
1968 return res;
1972 /**********************************************************************
1973 * MENUEX_ParseResource
1975 * Parse an extended menu resource and add items to the menu.
1976 * Return a pointer to the end of the resource.
1978 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1980 WORD resinfo;
1981 do {
1982 MENUITEMINFOW mii;
1984 mii.cbSize = sizeof(mii);
1985 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1986 mii.fType = GET_DWORD(res);
1987 res += sizeof(DWORD);
1988 mii.fState = GET_DWORD(res);
1989 res += sizeof(DWORD);
1990 mii.wID = GET_DWORD(res);
1991 res += sizeof(DWORD);
1992 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1993 res += sizeof(WORD);
1994 /* Align the text on a word boundary. */
1995 res += (~((int)res - 1)) & 1;
1996 mii.dwTypeData = (LPWSTR) res;
1997 res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
1998 /* Align the following fields on a dword boundary. */
1999 res += (~((int)res - 1)) & 3;
2001 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2003 LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
2004 0, mii.dwTypeData);
2005 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2006 mii.fType, mii.fState, mii.wID, resinfo, newstr);
2007 HeapFree( GetProcessHeap(), 0, newstr );
2010 if (resinfo & 1) { /* Pop-up? */
2011 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2012 res += sizeof(DWORD);
2013 mii.hSubMenu = CreatePopupMenu();
2014 if (!mii.hSubMenu)
2015 return NULL;
2016 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2017 DestroyMenu(mii.hSubMenu);
2018 return NULL;
2020 mii.fMask |= MIIM_SUBMENU;
2021 mii.fType |= MF_POPUP;
2023 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2024 } while (!(resinfo & MF_END));
2025 return res;
2029 /***********************************************************************
2030 * MENU_GetSubPopup
2032 * Return the handle of the selected sub-popup menu (if any).
2034 static HMENU MENU_GetSubPopup( HMENU hmenu )
2036 POPUPMENU *menu;
2037 MENUITEM *item;
2039 menu = MENU_GetMenu( hmenu );
2041 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2043 item = &menu->items[menu->FocusedItem];
2044 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2045 return item->hSubMenu;
2046 return 0;
2050 /***********************************************************************
2051 * MENU_HideSubPopups
2053 * Hide the sub-popup menus of this menu.
2055 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2056 BOOL sendMenuSelect )
2058 POPUPMENU *menu = MENU_GetMenu( hmenu );
2060 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2062 if (menu && uSubPWndLevel)
2064 HMENU hsubmenu;
2065 POPUPMENU *submenu;
2066 MENUITEM *item;
2068 if (menu->FocusedItem != NO_SELECTED_ITEM)
2070 item = &menu->items[menu->FocusedItem];
2071 if (!(item->fType & MF_POPUP) ||
2072 !(item->fState & MF_MOUSESELECT)) return;
2073 item->fState &= ~MF_MOUSESELECT;
2074 hsubmenu = item->hSubMenu;
2075 } else return;
2077 submenu = MENU_GetMenu( hsubmenu );
2078 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2079 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2081 if (submenu->hWnd == MENU_GetTopPopupWnd()->hwndSelf )
2083 ShowWindow( submenu->hWnd, SW_HIDE );
2084 uSubPWndLevel = 0;
2086 else
2088 DestroyWindow( submenu->hWnd );
2089 submenu->hWnd = 0;
2091 MENU_ReleaseTopPopupWnd();
2096 /***********************************************************************
2097 * MENU_ShowSubPopup
2099 * Display the sub-menu of the selected item of this menu.
2100 * Return the handle of the submenu, or hmenu if no submenu to display.
2102 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2103 BOOL selectFirst, UINT wFlags )
2105 RECT rect;
2106 POPUPMENU *menu;
2107 MENUITEM *item;
2108 WND *wndPtr;
2109 HDC hdc;
2111 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2113 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2115 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
2116 (menu->FocusedItem == NO_SELECTED_ITEM))
2118 WIN_ReleaseWndPtr(wndPtr);
2119 return hmenu;
2122 item = &menu->items[menu->FocusedItem];
2123 if (!(item->fType & MF_POPUP) ||
2124 (item->fState & (MF_GRAYED | MF_DISABLED)))
2126 WIN_ReleaseWndPtr(wndPtr);
2127 return hmenu;
2130 /* message must be send before using item,
2131 because nearly everything may by changed by the application ! */
2133 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2134 if (!(wFlags & TPM_NONOTIFY))
2135 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2136 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2138 item = &menu->items[menu->FocusedItem];
2139 rect = item->rect;
2141 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2142 if (!(item->fState & MF_HILITE))
2144 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2145 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2147 SelectObject( hdc, hMenuFont);
2149 item->fState |= MF_HILITE;
2150 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2151 ReleaseDC( menu->hWnd, hdc );
2153 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2154 item->rect = rect;
2156 item->fState |= MF_MOUSESELECT;
2158 if (IS_SYSTEM_MENU(menu))
2160 MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, GetClassLongA(wndPtr->hwndSelf, GCL_STYLE));
2162 NC_GetSysPopupPos( wndPtr, &rect );
2163 rect.top = rect.bottom;
2164 rect.right = GetSystemMetrics(SM_CXSIZE);
2165 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2167 else
2169 if (menu->wFlags & MF_POPUP)
2171 rect.left = wndPtr->rectWindow.left + item->rect.right - GetSystemMetrics(SM_CXBORDER);
2172 rect.top = wndPtr->rectWindow.top + item->rect.top;
2173 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2174 rect.bottom = item->rect.top - item->rect.bottom;
2176 else
2178 rect.left = wndPtr->rectWindow.left + item->rect.left;
2179 rect.top = wndPtr->rectWindow.top + item->rect.bottom;
2180 rect.right = item->rect.right - item->rect.left;
2181 rect.bottom = item->rect.bottom - item->rect.top;
2185 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2186 rect.left, rect.top, rect.right, rect.bottom );
2187 if (selectFirst)
2188 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2189 WIN_ReleaseWndPtr(wndPtr);
2190 return item->hSubMenu;
2195 /**********************************************************************
2196 * MENU_IsMenuActive
2198 BOOL MENU_IsMenuActive(void)
2200 return pTopPopupWnd && (pTopPopupWnd->dwStyle & WS_VISIBLE);
2203 /***********************************************************************
2204 * MENU_PtMenu
2206 * Walks menu chain trying to find a menu pt maps to.
2208 static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2210 POPUPMENU *menu = MENU_GetMenu( hMenu );
2211 register UINT ht = menu->FocusedItem;
2213 /* try subpopup first (if any) */
2214 ht = (ht != NO_SELECTED_ITEM &&
2215 (menu->items[ht].fType & MF_POPUP) &&
2216 (menu->items[ht].fState & MF_MOUSESELECT))
2217 ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
2219 if( !ht ) /* check the current window (avoiding WM_HITTEST) */
2221 ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt );
2222 if( menu->wFlags & MF_POPUP )
2223 ht = (ht != (UINT)HTNOWHERE &&
2224 ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
2225 else
2227 WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
2229 ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu)
2230 : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0;
2231 WIN_ReleaseWndPtr(wndPtr);
2234 return (HMENU)ht;
2237 /***********************************************************************
2238 * MENU_ExecFocusedItem
2240 * Execute a menu item (for instance when user pressed Enter).
2241 * Return the wID of the executed item. Otherwise, -1 indicating
2242 * that no menu item was executed;
2243 * Have to receive the flags for the TrackPopupMenu options to avoid
2244 * sending unwanted message.
2247 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2249 MENUITEM *item;
2250 POPUPMENU *menu = MENU_GetMenu( hMenu );
2252 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2254 if (!menu || !menu->nItems ||
2255 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2257 item = &menu->items[menu->FocusedItem];
2259 TRACE("%08x %08x %08x\n",
2260 hMenu, item->wID, item->hSubMenu);
2262 if (!(item->fType & MF_POPUP))
2264 if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
2266 /* If TPM_RETURNCMD is set you return the id, but
2267 do not send a message to the owner */
2268 if(!(wFlags & TPM_RETURNCMD))
2270 if( menu->wFlags & MF_SYSMENU )
2271 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2272 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2273 else
2274 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2276 return item->wID;
2279 else
2280 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2282 return -1;
2285 /***********************************************************************
2286 * MENU_SwitchTracking
2288 * Helper function for menu navigation routines.
2290 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2292 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2293 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2295 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2297 if( pmt->hTopMenu != hPtMenu &&
2298 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2300 /* both are top level menus (system and menu-bar) */
2301 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2302 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2303 pmt->hTopMenu = hPtMenu;
2305 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2306 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2310 /***********************************************************************
2311 * MENU_ButtonDown
2313 * Return TRUE if we can go on with menu tracking.
2315 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2317 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2319 if (hPtMenu)
2321 UINT id = 0;
2322 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2323 MENUITEM *item;
2325 if( IS_SYSTEM_MENU(ptmenu) )
2326 item = ptmenu->items;
2327 else
2328 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2330 if( item )
2332 if( ptmenu->FocusedItem != id )
2333 MENU_SwitchTracking( pmt, hPtMenu, id );
2335 /* If the popup menu is not already "popped" */
2336 if(!(item->fState & MF_MOUSESELECT ))
2338 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2340 /* In win31, a newly popped menu always remain opened for the next buttonup */
2341 if(TWEAK_WineLook == WIN31_LOOK)
2342 ptmenu->bTimeToHide = FALSE;
2345 return TRUE;
2347 /* Else the click was on the menu bar, finish the tracking */
2349 return FALSE;
2352 /***********************************************************************
2353 * MENU_ButtonUp
2355 * Return the value of MENU_ExecFocusedItem if
2356 * the selected item was not a popup. Else open the popup.
2357 * A -1 return value indicates that we go on with menu tracking.
2360 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2362 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2364 if (hPtMenu)
2366 UINT id = 0;
2367 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2368 MENUITEM *item;
2370 if( IS_SYSTEM_MENU(ptmenu) )
2371 item = ptmenu->items;
2372 else
2373 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2375 if( item && (ptmenu->FocusedItem == id ))
2377 if( !(item->fType & MF_POPUP) )
2378 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2380 /* If we are dealing with the top-level menu and that this */
2381 /* is a click on an already "poppped" item */
2382 /* Stop the menu tracking and close the opened submenus */
2383 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2384 return 0;
2386 ptmenu->bTimeToHide = TRUE;
2388 return -1;
2392 /***********************************************************************
2393 * MENU_MouseMove
2395 * Return TRUE if we can go on with menu tracking.
2397 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2399 UINT id = NO_SELECTED_ITEM;
2400 POPUPMENU *ptmenu = NULL;
2402 if( hPtMenu )
2404 ptmenu = MENU_GetMenu( hPtMenu );
2405 if( IS_SYSTEM_MENU(ptmenu) )
2406 id = 0;
2407 else
2408 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2411 if( id == NO_SELECTED_ITEM )
2413 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2414 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2417 else if( ptmenu->FocusedItem != id )
2419 MENU_SwitchTracking( pmt, hPtMenu, id );
2420 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2422 return TRUE;
2426 /***********************************************************************
2427 * MENU_DoNextMenu
2429 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2431 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2433 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2435 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2436 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2438 WND* wndPtr;
2439 HMENU hNewMenu;
2440 HWND hNewWnd;
2441 UINT id = 0;
2442 LRESULT l = SendMessageA( pmt->hOwnerWnd, WM_NEXTMENU, vk,
2443 (IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
2445 TRACE("%04x [%04x] -> %04x [%04x]\n",
2446 (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
2448 if( l == 0 )
2450 wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
2452 hNewWnd = pmt->hOwnerWnd;
2453 if( IS_SYSTEM_MENU(menu) )
2455 /* switch to the menu bar */
2457 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
2459 WIN_ReleaseWndPtr(wndPtr);
2460 return FALSE;
2463 hNewMenu = wndPtr->wIDmenu;
2464 if( vk == VK_LEFT )
2466 menu = MENU_GetMenu( hNewMenu );
2467 id = menu->nItems - 1;
2470 else if( wndPtr->dwStyle & WS_SYSMENU )
2472 /* switch to the system menu */
2473 hNewMenu = wndPtr->hSysMenu;
2475 else
2477 WIN_ReleaseWndPtr(wndPtr);
2478 return FALSE;
2480 WIN_ReleaseWndPtr(wndPtr);
2482 else /* application returned a new menu to switch to */
2484 hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
2486 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2488 wndPtr = WIN_FindWndPtr(hNewWnd);
2490 if( wndPtr->dwStyle & WS_SYSMENU &&
2491 GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
2493 /* get the real system menu */
2494 hNewMenu = wndPtr->hSysMenu;
2496 else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
2498 /* FIXME: Not sure what to do here, perhaps,
2499 * try to track hNewMenu as a popup? */
2501 TRACE(" -- got confused.\n");
2502 WIN_ReleaseWndPtr(wndPtr);
2503 return FALSE;
2505 WIN_ReleaseWndPtr(wndPtr);
2507 else return FALSE;
2510 if( hNewMenu != pmt->hTopMenu )
2512 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2513 FALSE, 0 );
2514 if( pmt->hCurrentMenu != pmt->hTopMenu )
2515 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2518 if( hNewWnd != pmt->hOwnerWnd )
2520 ReleaseCapture();
2521 pmt->hOwnerWnd = hNewWnd;
2522 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2525 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2526 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2528 return TRUE;
2530 return FALSE;
2533 /***********************************************************************
2534 * MENU_SuspendPopup
2536 * The idea is not to show the popup if the next input message is
2537 * going to hide it anyway.
2539 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2541 MSG msg;
2543 msg.hwnd = pmt->hOwnerWnd;
2545 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2546 pmt->trackFlags |= TF_SKIPREMOVE;
2548 switch( uMsg )
2550 case WM_KEYDOWN:
2551 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2552 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2554 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2555 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2556 if( msg.message == WM_KEYDOWN &&
2557 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2559 pmt->trackFlags |= TF_SUSPENDPOPUP;
2560 return TRUE;
2563 break;
2566 /* failures go through this */
2567 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2568 return FALSE;
2571 /***********************************************************************
2572 * MENU_KeyLeft
2574 * Handle a VK_LEFT key event in a menu.
2576 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2578 POPUPMENU *menu;
2579 HMENU hmenutmp, hmenuprev;
2580 UINT prevcol;
2582 hmenuprev = hmenutmp = pmt->hTopMenu;
2583 menu = MENU_GetMenu( hmenutmp );
2585 /* Try to move 1 column left (if possible) */
2586 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2587 NO_SELECTED_ITEM ) {
2589 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2590 prevcol, TRUE, 0 );
2591 return;
2594 /* close topmost popup */
2595 while (hmenutmp != pmt->hCurrentMenu)
2597 hmenuprev = hmenutmp;
2598 hmenutmp = MENU_GetSubPopup( hmenuprev );
2601 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2602 pmt->hCurrentMenu = hmenuprev;
2604 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2606 /* move menu bar selection if no more popups are left */
2608 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2609 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2611 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2613 /* A sublevel menu was displayed - display the next one
2614 * unless there is another displacement coming up */
2616 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2617 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2618 pmt->hTopMenu, TRUE, wFlags);
2624 /***********************************************************************
2625 * MENU_KeyRight
2627 * Handle a VK_RIGHT key event in a menu.
2629 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2631 HMENU hmenutmp;
2632 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2633 UINT nextcol;
2635 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2636 pmt->hCurrentMenu,
2637 (MENU_GetMenu(pmt->hCurrentMenu))->
2638 items[0].text,
2639 pmt->hTopMenu, menu->items[0].text );
2641 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2643 /* If already displaying a popup, try to display sub-popup */
2645 hmenutmp = pmt->hCurrentMenu;
2646 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2648 /* if subpopup was displayed then we are done */
2649 if (hmenutmp != pmt->hCurrentMenu) return;
2652 /* Check to see if there's another column */
2653 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2654 NO_SELECTED_ITEM ) {
2655 TRACE("Going to %d.\n", nextcol );
2656 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2657 nextcol, TRUE, 0 );
2658 return;
2661 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2663 if( pmt->hCurrentMenu != pmt->hTopMenu )
2665 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2666 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2667 } else hmenutmp = 0;
2669 /* try to move to the next item */
2670 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2671 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2673 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2674 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2675 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2676 pmt->hTopMenu, TRUE, wFlags);
2680 /***********************************************************************
2681 * MENU_TrackMenu
2683 * Menu tracking code.
2685 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2686 HWND hwnd, const RECT *lprect )
2688 MSG msg;
2689 POPUPMENU *menu;
2690 BOOL fRemove;
2691 INT executedMenuId = -1;
2692 MTRACKER mt;
2693 BOOL enterIdleSent = FALSE;
2695 mt.trackFlags = 0;
2696 mt.hCurrentMenu = hmenu;
2697 mt.hTopMenu = hmenu;
2698 mt.hOwnerWnd = hwnd;
2699 mt.pt.x = x;
2700 mt.pt.y = y;
2702 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2703 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2704 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2706 fEndMenu = FALSE;
2707 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2709 if (wFlags & TPM_BUTTONDOWN)
2711 /* Get the result in order to start the tracking or not */
2712 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2713 fEndMenu = !fRemove;
2716 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2718 while (!fEndMenu)
2720 menu = MENU_GetMenu( mt.hCurrentMenu );
2721 msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2723 /* we have to keep the message in the queue until it's
2724 * clear that menu loop is not over yet. */
2726 if (!MSG_InternalGetMessage( QMSG_WIN32A, &msg, msg.hwnd, mt.hOwnerWnd,
2727 MSGF_MENU, PM_NOREMOVE, !enterIdleSent, &enterIdleSent )) break;
2729 /* check if EndMenu() tried to cancel us, by posting this message */
2730 if(msg.message == WM_CANCELMODE)
2732 /* we are now out of the loop */
2733 fEndMenu = TRUE;
2735 /* remove the message from the queue */
2736 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2738 /* break out of internal loop, ala ESCAPE */
2739 break;
2742 TranslateMessage( &msg );
2743 mt.pt = msg.pt;
2745 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2746 enterIdleSent=FALSE;
2748 fRemove = FALSE;
2749 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2751 /* Find a menu for this mouse event */
2752 hmenu = MENU_PtMenu( mt.hTopMenu, msg.pt );
2754 switch(msg.message)
2756 /* no WM_NC... messages in captured state */
2758 case WM_RBUTTONDBLCLK:
2759 case WM_RBUTTONDOWN:
2760 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2761 /* fall through */
2762 case WM_LBUTTONDBLCLK:
2763 case WM_LBUTTONDOWN:
2764 /* If the message belongs to the menu, removes it from the queue */
2765 /* Else, end menu tracking */
2766 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2767 fEndMenu = !fRemove;
2768 break;
2770 case WM_RBUTTONUP:
2771 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2772 /* fall through */
2773 case WM_LBUTTONUP:
2774 /* Check if a menu was selected by the mouse */
2775 if (hmenu)
2777 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2779 /* End the loop if executedMenuId is an item ID */
2780 /* or if the job was done (executedMenuId = 0). */
2781 fEndMenu = fRemove = (executedMenuId != -1);
2783 /* No menu was selected by the mouse */
2784 /* if the function was called by TrackPopupMenu, continue
2785 with the menu tracking. If not, stop it */
2786 else
2787 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2789 break;
2791 case WM_MOUSEMOVE:
2792 /* In win95 winelook, the selected menu item must be changed every time the
2793 mouse moves. In Win31 winelook, the mouse button has to be held down */
2795 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2796 ( (msg.wParam & MK_LBUTTON) ||
2797 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2799 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2801 } /* switch(msg.message) - mouse */
2803 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2805 fRemove = TRUE; /* Keyboard messages are always removed */
2806 switch(msg.message)
2808 case WM_KEYDOWN:
2809 switch(msg.wParam)
2811 case VK_HOME:
2812 case VK_END:
2813 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2814 NO_SELECTED_ITEM, FALSE, 0 );
2815 /* fall through */
2816 case VK_UP:
2817 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2818 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2819 break;
2821 case VK_DOWN: /* If on menu bar, pull-down the menu */
2823 menu = MENU_GetMenu( mt.hCurrentMenu );
2824 if (!(menu->wFlags & MF_POPUP))
2825 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2826 else /* otherwise try to move selection */
2827 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2828 break;
2830 case VK_LEFT:
2831 MENU_KeyLeft( &mt, wFlags );
2832 break;
2834 case VK_RIGHT:
2835 MENU_KeyRight( &mt, wFlags );
2836 break;
2838 case VK_ESCAPE:
2839 fEndMenu = TRUE;
2840 break;
2842 case VK_F1:
2844 HELPINFO hi;
2845 hi.cbSize = sizeof(HELPINFO);
2846 hi.iContextType = HELPINFO_MENUITEM;
2847 if (menu->FocusedItem == NO_SELECTED_ITEM)
2848 hi.iCtrlId = 0;
2849 else
2850 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2851 hi.hItemHandle = hmenu;
2852 hi.dwContextId = menu->dwContextHelpID;
2853 hi.MousePos = msg.pt;
2854 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2855 break;
2858 default:
2859 break;
2861 break; /* WM_KEYDOWN */
2863 case WM_SYSKEYDOWN:
2864 switch(msg.wParam)
2866 case VK_MENU:
2867 fEndMenu = TRUE;
2868 break;
2871 break; /* WM_SYSKEYDOWN */
2873 case WM_CHAR:
2875 UINT pos;
2877 if (msg.wParam == '\r' || msg.wParam == ' ')
2879 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2880 fEndMenu = (executedMenuId != -1);
2882 break;
2885 /* Hack to avoid control chars. */
2886 /* We will find a better way real soon... */
2887 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2889 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
2890 LOWORD(msg.wParam), FALSE );
2891 if (pos == (UINT)-2) fEndMenu = TRUE;
2892 else if (pos == (UINT)-1) MessageBeep(0);
2893 else
2895 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2896 TRUE, 0 );
2897 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2898 fEndMenu = (executedMenuId != -1);
2901 break;
2902 } /* switch(msg.message) - kbd */
2904 else
2906 DispatchMessageA( &msg );
2909 if (!fEndMenu) fRemove = TRUE;
2911 /* finally remove message from the queue */
2913 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2914 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2915 else mt.trackFlags &= ~TF_SKIPREMOVE;
2918 ReleaseCapture();
2920 /* If dropdown is still painted and the close box is clicked on
2921 then the menu will be destroyed as part of the DispatchMessage above.
2922 This will then invalidate the menu handle in mt.hTopMenu. We should
2923 check for this first. */
2924 if( IsMenu( mt.hTopMenu ) )
2926 menu = MENU_GetMenu( mt.hTopMenu );
2928 if( IsWindow( mt.hOwnerWnd ) )
2930 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2932 if (menu && menu->wFlags & MF_POPUP)
2934 ShowWindow( menu->hWnd, SW_HIDE );
2935 uSubPWndLevel = 0;
2937 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2938 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2941 /* Reset the variable for hiding menu */
2942 if( menu ) menu->bTimeToHide = FALSE;
2945 /* The return value is only used by TrackPopupMenu */
2946 return ((executedMenuId != -1) ? executedMenuId : 0);
2949 /***********************************************************************
2950 * MENU_InitTracking
2952 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
2954 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
2956 HideCaret(0);
2958 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2959 if (!(wFlags & TPM_NONOTIFY))
2960 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2962 SendMessageA( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
2964 if (!(wFlags & TPM_NONOTIFY))
2965 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
2967 return TRUE;
2969 /***********************************************************************
2970 * MENU_ExitTracking
2972 static BOOL MENU_ExitTracking(HWND hWnd)
2974 TRACE("hwnd=0x%04x\n", hWnd);
2976 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2977 ShowCaret(0);
2978 return TRUE;
2981 /***********************************************************************
2982 * MENU_TrackMouseMenuBar
2984 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2986 void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt )
2988 HWND hWnd = wndPtr->hwndSelf;
2989 HMENU hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
2990 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2992 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr, ht, pt.x, pt.y);
2994 if (IsMenu(hMenu))
2996 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2997 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
2998 MENU_ExitTracking(hWnd);
3003 /***********************************************************************
3004 * MENU_TrackKbdMenuBar
3006 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3008 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
3010 UINT uItem = NO_SELECTED_ITEM;
3011 HMENU hTrackMenu;
3012 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3014 /* find window that has a menu */
3016 while( wndPtr->dwStyle & WS_CHILD)
3017 if( !(wndPtr = wndPtr->parent) ) return;
3019 /* check if we have to track a system menu */
3021 if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) ||
3022 !wndPtr->wIDmenu || vkey == VK_SPACE )
3024 if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
3025 hTrackMenu = wndPtr->hSysMenu;
3026 uItem = 0;
3027 wParam |= HTSYSMENU; /* prevent item lookup */
3029 else
3030 hTrackMenu = wndPtr->wIDmenu;
3032 if (IsMenu( hTrackMenu ))
3034 MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu, FALSE, wFlags );
3036 if( vkey && vkey != VK_SPACE )
3038 uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu,
3039 vkey, (wParam & HTSYSMENU) );
3040 if( uItem >= (UINT)(-2) )
3042 if( uItem == (UINT)(-1) ) MessageBeep(0);
3043 hTrackMenu = 0;
3047 if( hTrackMenu )
3049 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE, 0 );
3051 if( uItem == NO_SELECTED_ITEM )
3052 MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
3053 else if( vkey )
3054 PostMessageA( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
3056 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, wndPtr->hwndSelf, NULL );
3059 MENU_ExitTracking (wndPtr->hwndSelf);
3064 /**********************************************************************
3065 * TrackPopupMenu16 (USER.416)
3067 BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
3068 INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
3070 RECT r;
3071 if (lpRect)
3072 CONV_RECT16TO32( lpRect, &r );
3073 return TrackPopupMenu( hMenu, wFlags, x, y, nReserved, hWnd,
3074 lpRect ? &r : NULL );
3078 /**********************************************************************
3079 * TrackPopupMenu (USER32.549)
3081 * Like the win32 API, the function return the command ID only if the
3082 * flag TPM_RETURNCMD is on.
3085 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3086 INT nReserved, HWND hWnd, const RECT *lpRect )
3088 BOOL ret = FALSE;
3090 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3092 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3093 if (!(wFlags & TPM_NONOTIFY))
3094 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3096 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3097 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3098 MENU_ExitTracking(hWnd);
3100 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3101 ret = 1;
3103 return ret;
3106 /**********************************************************************
3107 * TrackPopupMenuEx (USER32.550)
3109 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3110 HWND hWnd, LPTPMPARAMS lpTpm )
3112 FIXME("not fully implemented\n" );
3113 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3114 lpTpm ? &lpTpm->rcExclude : NULL );
3117 /***********************************************************************
3118 * PopupMenuWndProc
3120 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3122 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
3123 LPARAM lParam )
3125 WND* wndPtr = WIN_FindWndPtr(hwnd);
3126 LRESULT retvalue;
3128 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3129 hwnd, message, wParam, lParam);
3131 switch(message)
3133 case WM_CREATE:
3135 CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
3136 SetWindowLongA( hwnd, 0, (LONG)cs->lpCreateParams );
3137 retvalue = 0;
3138 goto END;
3141 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3142 retvalue = MA_NOACTIVATE;
3143 goto END;
3145 case WM_PAINT:
3147 PAINTSTRUCT ps;
3148 BeginPaint( hwnd, &ps );
3149 MENU_DrawPopupMenu( hwnd, ps.hdc,
3150 (HMENU)GetWindowLongA( hwnd, 0 ) );
3151 EndPaint( hwnd, &ps );
3152 retvalue = 0;
3153 goto END;
3155 case WM_ERASEBKGND:
3156 retvalue = 1;
3157 goto END;
3159 case WM_DESTROY:
3161 /* zero out global pointer in case resident popup window
3162 * was somehow destroyed. */
3164 if(MENU_GetTopPopupWnd() )
3166 if( hwnd == pTopPopupWnd->hwndSelf )
3168 ERR("resident popup destroyed!\n");
3170 MENU_DestroyTopPopupWnd();
3171 uSubPWndLevel = 0;
3173 else
3174 uSubPWndLevel--;
3175 MENU_ReleaseTopPopupWnd();
3177 break;
3179 case WM_SHOWWINDOW:
3181 if( wParam )
3183 if( !(*(HMENU*)wndPtr->wExtra) )
3184 ERR("no menu to display\n");
3186 else
3187 *(HMENU*)wndPtr->wExtra = 0;
3188 break;
3190 case MM_SETMENUHANDLE:
3192 *(HMENU*)wndPtr->wExtra = (HMENU)wParam;
3193 break;
3195 case MM_GETMENUHANDLE:
3197 retvalue = *(HMENU*)wndPtr->wExtra;
3198 goto END;
3200 default:
3201 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
3202 goto END;
3204 retvalue = 0;
3205 END:
3206 WIN_ReleaseWndPtr(wndPtr);
3207 return retvalue;
3211 /***********************************************************************
3212 * MENU_GetMenuBarHeight
3214 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3216 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3217 INT orgX, INT orgY )
3219 HDC hdc;
3220 RECT rectBar;
3221 WND *wndPtr;
3222 LPPOPUPMENU lppop;
3223 UINT retvalue;
3225 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3226 hwnd, menubarWidth, orgX, orgY );
3228 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
3229 return 0;
3231 if (!(lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu)))
3233 WIN_ReleaseWndPtr(wndPtr);
3234 return 0;
3237 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3238 SelectObject( hdc, hMenuFont);
3239 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3240 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3241 ReleaseDC( hwnd, hdc );
3242 retvalue = lppop->Height;
3243 WIN_ReleaseWndPtr(wndPtr);
3244 return retvalue;
3248 /*******************************************************************
3249 * ChangeMenu16 (USER.153)
3251 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3252 UINT16 id, UINT16 flags )
3254 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3255 hMenu, pos, (DWORD)data, id, flags );
3256 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3257 id, data );
3259 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3260 /* for MF_DELETE. We should check the parameters for all others */
3261 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3263 if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3264 if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3265 id, data );
3266 if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
3267 flags & MF_BYPOSITION ? pos : id,
3268 flags & ~MF_REMOVE );
3269 /* Default: MF_INSERT */
3270 return InsertMenu16( hMenu, pos, flags, id, data );
3274 /*******************************************************************
3275 * ChangeMenuA (USER32.23)
3277 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3278 UINT id, UINT flags )
3280 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3281 hMenu, pos, (DWORD)data, id, flags );
3282 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3283 id, data );
3284 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3285 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3286 id, data );
3287 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3288 flags & MF_BYPOSITION ? pos : id,
3289 flags & ~MF_REMOVE );
3290 /* Default: MF_INSERT */
3291 return InsertMenuA( hMenu, pos, flags, id, data );
3295 /*******************************************************************
3296 * ChangeMenuW (USER32.24)
3298 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3299 UINT id, UINT flags )
3301 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3302 hMenu, pos, (DWORD)data, id, flags );
3303 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3304 id, data );
3305 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3306 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3307 id, data );
3308 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3309 flags & MF_BYPOSITION ? pos : id,
3310 flags & ~MF_REMOVE );
3311 /* Default: MF_INSERT */
3312 return InsertMenuW( hMenu, pos, flags, id, data );
3316 /*******************************************************************
3317 * CheckMenuItem16 (USER.154)
3319 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
3321 return (BOOL16)CheckMenuItem( hMenu, id, flags );
3325 /*******************************************************************
3326 * CheckMenuItem (USER32.46)
3328 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3330 MENUITEM *item;
3331 DWORD ret;
3333 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3334 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3335 ret = item->fState & MF_CHECKED;
3336 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3337 else item->fState &= ~MF_CHECKED;
3338 return ret;
3342 /**********************************************************************
3343 * EnableMenuItem16 (USER.155)
3345 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3347 return EnableMenuItem( hMenu, wItemID, wFlags );
3351 /**********************************************************************
3352 * EnableMenuItem (USER32.170)
3354 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3356 UINT oldflags;
3357 MENUITEM *item;
3358 POPUPMENU *menu;
3360 TRACE("(%04x, %04X, %04X) !\n",
3361 hMenu, wItemID, wFlags);
3363 /* Get the Popupmenu to access the owner menu */
3364 if (!(menu = MENU_GetMenu(hMenu)))
3365 return (UINT)-1;
3367 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3368 return (UINT)-1;
3370 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3371 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3373 /* In win95 if the close item in the system menu change update the close button */
3374 if (TWEAK_WineLook == WIN95_LOOK)
3375 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3377 if (menu->hSysMenuOwner != 0)
3379 POPUPMENU* parentMenu;
3381 /* Get the parent menu to access*/
3382 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3383 return (UINT)-1;
3385 /* Refresh the frame to reflect the change*/
3386 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3387 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3391 return oldflags;
3395 /*******************************************************************
3396 * GetMenuString16 (USER.161)
3398 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3399 LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
3401 return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
3405 /*******************************************************************
3406 * GetMenuStringA (USER32.268)
3408 INT WINAPI GetMenuStringA(
3409 HMENU hMenu, /* [in] menuhandle */
3410 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3411 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3412 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3413 UINT wFlags /* [in] MF_ flags */
3415 MENUITEM *item;
3417 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3418 hMenu, wItemID, str, nMaxSiz, wFlags );
3419 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3420 if (!IS_STRING_ITEM(item->fType)) return 0;
3421 if (!str || !nMaxSiz) return strlen(item->text);
3422 str[0] = '\0';
3423 lstrcpynA( str, item->text, nMaxSiz );
3424 TRACE("returning '%s'\n", str );
3425 return strlen(str);
3429 /*******************************************************************
3430 * GetMenuStringW (USER32.269)
3432 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3433 LPWSTR str, INT nMaxSiz, UINT wFlags )
3435 MENUITEM *item;
3437 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3438 hMenu, wItemID, str, nMaxSiz, wFlags );
3439 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3440 if (!IS_STRING_ITEM(item->fType)) return 0;
3441 if (!str || !nMaxSiz) return strlen(item->text);
3442 str[0] = '\0';
3443 lstrcpynAtoW( str, item->text, nMaxSiz );
3444 return lstrlenW(str);
3448 /**********************************************************************
3449 * HiliteMenuItem16 (USER.162)
3451 BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
3452 UINT16 wHilite )
3454 return HiliteMenuItem( hWnd, hMenu, wItemID, wHilite );
3458 /**********************************************************************
3459 * HiliteMenuItem (USER32.318)
3461 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3462 UINT wHilite )
3464 LPPOPUPMENU menu;
3465 TRACE("(%04x, %04x, %04x, %04x);\n",
3466 hWnd, hMenu, wItemID, wHilite);
3467 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3468 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3469 if (menu->FocusedItem == wItemID) return TRUE;
3470 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3471 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3472 return TRUE;
3476 /**********************************************************************
3477 * GetMenuState16 (USER.250)
3479 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3481 return GetMenuState( hMenu, wItemID, wFlags );
3485 /**********************************************************************
3486 * GetMenuState (USER32.267)
3488 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3490 MENUITEM *item;
3491 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3492 hMenu, wItemID, wFlags);
3493 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3494 debug_print_menuitem (" item: ", item, "");
3495 if (item->fType & MF_POPUP)
3497 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3498 if (!menu) return -1;
3499 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3501 else
3503 /* We used to (from way back then) mask the result to 0xff. */
3504 /* I don't know why and it seems wrong as the documented */
3505 /* return flag MF_SEPARATOR is outside that mask. */
3506 return (item->fType | item->fState);
3511 /**********************************************************************
3512 * GetMenuItemCount16 (USER.263)
3514 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3516 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3517 if (!menu) return -1;
3518 TRACE("(%04x) returning %d\n",
3519 hMenu, menu->nItems );
3520 return menu->nItems;
3524 /**********************************************************************
3525 * GetMenuItemCount (USER32.262)
3527 INT WINAPI GetMenuItemCount( HMENU hMenu )
3529 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3530 if (!menu) return -1;
3531 TRACE("(%04x) returning %d\n",
3532 hMenu, menu->nItems );
3533 return menu->nItems;
3536 /**********************************************************************
3537 * GetMenuItemID16 (USER.264)
3539 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3541 return (UINT16) GetMenuItemID (hMenu, nPos);
3544 /**********************************************************************
3545 * GetMenuItemID (USER32.263)
3547 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3549 MENUITEM * lpmi;
3551 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3552 if (lpmi->fType & MF_POPUP) return -1;
3553 return lpmi->wID;
3557 /*******************************************************************
3558 * InsertMenu16 (USER.410)
3560 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3561 UINT16 id, SEGPTR data )
3563 UINT pos32 = (UINT)pos;
3564 if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3565 if (IS_STRING_ITEM(flags) && data)
3566 return InsertMenuA( hMenu, pos32, flags, id,
3567 (LPSTR)PTR_SEG_TO_LIN(data) );
3568 return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3572 /*******************************************************************
3573 * InsertMenuA (USER32.322)
3575 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3576 UINT id, LPCSTR str )
3578 MENUITEM *item;
3580 if (IS_STRING_ITEM(flags) && str)
3581 TRACE("hMenu %04x, pos %d, flags %08x, "
3582 "id %04x, str '%s'\n",
3583 hMenu, pos, flags, id, str );
3584 else TRACE("hMenu %04x, pos %d, flags %08x, "
3585 "id %04x, str %08lx (not a string)\n",
3586 hMenu, pos, flags, id, (DWORD)str );
3588 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3590 if (!(MENU_SetItemData( item, flags, id, str )))
3592 RemoveMenu( hMenu, pos, flags );
3593 return FALSE;
3596 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3597 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3599 item->hCheckBit = item->hUnCheckBit = 0;
3600 return TRUE;
3604 /*******************************************************************
3605 * InsertMenuW (USER32.325)
3607 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3608 UINT id, LPCWSTR str )
3610 BOOL ret;
3612 if (IS_STRING_ITEM(flags) && str)
3614 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3615 ret = InsertMenuA( hMenu, pos, flags, id, newstr );
3616 HeapFree( GetProcessHeap(), 0, newstr );
3617 return ret;
3619 else return InsertMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3623 /*******************************************************************
3624 * AppendMenu16 (USER.411)
3626 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3628 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3632 /*******************************************************************
3633 * AppendMenuA (USER32.5)
3635 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3636 UINT id, LPCSTR data )
3638 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3642 /*******************************************************************
3643 * AppendMenuW (USER32.6)
3645 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3646 UINT id, LPCWSTR data )
3648 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3652 /**********************************************************************
3653 * RemoveMenu16 (USER.412)
3655 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3657 return RemoveMenu( hMenu, nPos, wFlags );
3661 /**********************************************************************
3662 * RemoveMenu (USER32.441)
3664 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3666 LPPOPUPMENU menu;
3667 MENUITEM *item;
3669 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3670 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3671 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3673 /* Remove item */
3675 MENU_FreeItemData( item );
3677 if (--menu->nItems == 0)
3679 HeapFree( SystemHeap, 0, menu->items );
3680 menu->items = NULL;
3682 else
3684 while(nPos < menu->nItems)
3686 *item = *(item+1);
3687 item++;
3688 nPos++;
3690 menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
3691 menu->nItems * sizeof(MENUITEM) );
3693 return TRUE;
3697 /**********************************************************************
3698 * DeleteMenu16 (USER.413)
3700 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3702 return DeleteMenu( hMenu, nPos, wFlags );
3706 /**********************************************************************
3707 * DeleteMenu (USER32.129)
3709 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3711 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3712 if (!item) return FALSE;
3713 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3714 /* nPos is now the position of the item */
3715 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3716 return TRUE;
3720 /*******************************************************************
3721 * ModifyMenu16 (USER.414)
3723 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3724 UINT16 id, SEGPTR data )
3726 if (IS_STRING_ITEM(flags))
3727 return ModifyMenuA( hMenu, pos, flags, id,
3728 (LPSTR)PTR_SEG_TO_LIN(data) );
3729 return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3733 /*******************************************************************
3734 * ModifyMenuA (USER32.397)
3736 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3737 UINT id, LPCSTR str )
3739 MENUITEM *item;
3741 if (IS_STRING_ITEM(flags))
3743 TRACE("%04x %d %04x %04x '%s'\n",
3744 hMenu, pos, flags, id, str ? str : "#NULL#" );
3745 if (!str) return FALSE;
3747 else
3749 TRACE("%04x %d %04x %04x %08lx\n",
3750 hMenu, pos, flags, id, (DWORD)str );
3753 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3754 return MENU_SetItemData( item, flags, id, str );
3758 /*******************************************************************
3759 * ModifyMenuW (USER32.398)
3761 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3762 UINT id, LPCWSTR str )
3764 BOOL ret;
3766 if (IS_STRING_ITEM(flags) && str)
3768 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3769 ret = ModifyMenuA( hMenu, pos, flags, id, newstr );
3770 HeapFree( GetProcessHeap(), 0, newstr );
3771 return ret;
3773 else return ModifyMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3777 /**********************************************************************
3778 * CreatePopupMenu16 (USER.415)
3780 HMENU16 WINAPI CreatePopupMenu16(void)
3782 return CreatePopupMenu();
3786 /**********************************************************************
3787 * CreatePopupMenu (USER32.82)
3789 HMENU WINAPI CreatePopupMenu(void)
3791 HMENU hmenu;
3792 POPUPMENU *menu;
3794 if (!(hmenu = CreateMenu())) return 0;
3795 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
3796 menu->wFlags |= MF_POPUP;
3797 menu->bTimeToHide = FALSE;
3798 return hmenu;
3802 /**********************************************************************
3803 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3805 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3807 return MAKELONG( check_bitmap_width, check_bitmap_height );
3811 /**********************************************************************
3812 * SetMenuItemBitmaps16 (USER.418)
3814 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3815 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3817 return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3821 /**********************************************************************
3822 * SetMenuItemBitmaps (USER32.490)
3824 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3825 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3827 MENUITEM *item;
3828 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3829 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3830 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3832 if (!hNewCheck && !hNewUnCheck)
3834 item->fState &= ~MF_USECHECKBITMAPS;
3836 else /* Install new bitmaps */
3838 item->hCheckBit = hNewCheck;
3839 item->hUnCheckBit = hNewUnCheck;
3840 item->fState |= MF_USECHECKBITMAPS;
3842 return TRUE;
3846 /**********************************************************************
3847 * CreateMenu16 (USER.151)
3849 HMENU16 WINAPI CreateMenu16(void)
3851 return CreateMenu();
3855 /**********************************************************************
3856 * CreateMenu (USER32.81)
3858 HMENU WINAPI CreateMenu(void)
3860 HMENU hMenu;
3861 LPPOPUPMENU menu;
3862 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3863 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3865 ZeroMemory(menu, sizeof(POPUPMENU));
3866 menu->wMagic = MENU_MAGIC;
3867 menu->FocusedItem = NO_SELECTED_ITEM;
3868 menu->bTimeToHide = FALSE;
3870 TRACE("return %04x\n", hMenu );
3872 return hMenu;
3876 /**********************************************************************
3877 * DestroyMenu16 (USER.152)
3879 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3881 return DestroyMenu( hMenu );
3885 /**********************************************************************
3886 * DestroyMenu (USER32.134)
3888 BOOL WINAPI DestroyMenu( HMENU hMenu )
3890 TRACE("(%04x)\n", hMenu);
3892 /* Silently ignore attempts to destroy default system popup */
3894 if (hMenu && hMenu != MENU_DefSysPopup)
3896 LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3897 WND *pTPWnd = MENU_GetTopPopupWnd();
3899 if( pTPWnd && (hMenu == *(HMENU*)pTPWnd->wExtra) )
3900 *(UINT*)pTPWnd->wExtra = 0;
3902 if (!IS_A_MENU(lppop)) lppop = NULL;
3903 if ( lppop )
3905 lppop->wMagic = 0; /* Mark it as destroyed */
3907 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
3908 (!pTPWnd || (lppop->hWnd != pTPWnd->hwndSelf)))
3909 DestroyWindow( lppop->hWnd );
3911 if (lppop->items) /* recursively destroy submenus */
3913 int i;
3914 MENUITEM *item = lppop->items;
3915 for (i = lppop->nItems; i > 0; i--, item++)
3917 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3918 MENU_FreeItemData( item );
3920 HeapFree( SystemHeap, 0, lppop->items );
3922 USER_HEAP_FREE( hMenu );
3923 MENU_ReleaseTopPopupWnd();
3925 else
3927 MENU_ReleaseTopPopupWnd();
3928 return FALSE;
3931 return (hMenu != MENU_DefSysPopup);
3935 /**********************************************************************
3936 * GetSystemMenu16 (USER.156)
3938 HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
3940 return GetSystemMenu( hWnd, bRevert );
3944 /**********************************************************************
3945 * GetSystemMenu (USER32.291)
3947 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3949 WND *wndPtr = WIN_FindWndPtr( hWnd );
3950 HMENU retvalue = 0;
3952 if (wndPtr)
3954 if( wndPtr->hSysMenu )
3956 if( bRevert )
3958 DestroyMenu(wndPtr->hSysMenu);
3959 wndPtr->hSysMenu = 0;
3961 else
3963 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3964 if( menu )
3966 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3967 menu->items[0].hSubMenu = MENU_CopySysPopup();
3969 else
3971 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3972 wndPtr->hSysMenu, hWnd);
3973 wndPtr->hSysMenu = 0;
3978 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3979 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3981 if( wndPtr->hSysMenu )
3983 POPUPMENU *menu;
3984 retvalue = GetSubMenu16(wndPtr->hSysMenu, 0);
3986 /* Store the dummy sysmenu handle to facilitate the refresh */
3987 /* of the close button if the SC_CLOSE item change */
3988 menu = MENU_GetMenu(retvalue);
3989 if ( menu )
3990 menu->hSysMenuOwner = wndPtr->hSysMenu;
3992 WIN_ReleaseWndPtr(wndPtr);
3994 return bRevert ? 0 : retvalue;
3998 /*******************************************************************
3999 * SetSystemMenu16 (USER.280)
4001 BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
4003 return SetSystemMenu( hwnd, hMenu );
4007 /*******************************************************************
4008 * SetSystemMenu (USER32.508)
4010 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
4012 WND *wndPtr = WIN_FindWndPtr(hwnd);
4014 if (wndPtr)
4016 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
4017 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
4018 WIN_ReleaseWndPtr(wndPtr);
4019 return TRUE;
4021 return FALSE;
4025 /**********************************************************************
4026 * GetMenu16 (USER.157)
4028 HMENU16 WINAPI GetMenu16( HWND16 hWnd )
4030 return (HMENU16)GetMenu(hWnd);
4034 /**********************************************************************
4035 * GetMenu (USER32.257)
4037 HMENU WINAPI GetMenu( HWND hWnd )
4039 HMENU retvalue;
4040 WND * wndPtr = WIN_FindWndPtr(hWnd);
4042 if (!wndPtr) return 0;
4044 retvalue = (HMENU)wndPtr->wIDmenu;
4045 TRACE("for %swindow %04x returning %04x\n",
4046 (wndPtr->dwStyle & WS_CHILD) ? "child " : "", hWnd, retvalue);
4047 WIN_ReleaseWndPtr(wndPtr);
4048 return retvalue;
4052 /**********************************************************************
4053 * SetMenu16 (USER.158)
4055 BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
4057 return SetMenu( hWnd, hMenu );
4061 /**********************************************************************
4062 * SetMenu (USER32.487)
4064 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4066 WND * wndPtr = WIN_FindWndPtr(hWnd);
4067 BOOL res = FALSE;
4069 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4071 if (hMenu && !IsMenu(hMenu))
4073 WARN("hMenu is not a menu handle\n");
4074 goto exit;
4077 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4079 if (GetCapture() == hWnd) ReleaseCapture();
4081 wndPtr->wIDmenu = (UINT)hMenu;
4082 if (hMenu != 0)
4084 LPPOPUPMENU lpmenu;
4086 if (!(lpmenu = MENU_GetMenu(hMenu)))
4087 goto exit;
4089 lpmenu->hWnd = hWnd;
4090 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
4091 lpmenu->Height = 0; /* Make sure we recalculate the size */
4093 if (IsWindowVisible(hWnd))
4094 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4095 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4096 res = TRUE;
4098 exit:
4099 WIN_ReleaseWndPtr(wndPtr);
4100 return res;
4105 /**********************************************************************
4106 * GetSubMenu16 (USER.159)
4108 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
4110 return GetSubMenu( hMenu, nPos );
4114 /**********************************************************************
4115 * GetSubMenu (USER32.288)
4117 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4119 MENUITEM * lpmi;
4121 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4122 if (!(lpmi->fType & MF_POPUP)) return 0;
4123 return lpmi->hSubMenu;
4127 /**********************************************************************
4128 * DrawMenuBar16 (USER.160)
4130 void WINAPI DrawMenuBar16( HWND16 hWnd )
4132 DrawMenuBar( hWnd );
4136 /**********************************************************************
4137 * DrawMenuBar (USER32.161)
4139 BOOL WINAPI DrawMenuBar( HWND hWnd )
4141 LPPOPUPMENU lppop;
4142 WND *wndPtr = WIN_FindWndPtr(hWnd);
4143 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
4145 lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu);
4146 if (lppop == NULL)
4148 WIN_ReleaseWndPtr(wndPtr);
4149 return FALSE;
4152 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4153 lppop->hwndOwner = hWnd;
4154 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4155 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4156 WIN_ReleaseWndPtr(wndPtr);
4157 return TRUE;
4159 WIN_ReleaseWndPtr(wndPtr);
4160 return FALSE;
4164 /***********************************************************************
4165 * EndMenu (USER.187) (USER32.175)
4167 void WINAPI EndMenu(void)
4169 /* if we are in the menu code, and it is active */
4170 if (fEndMenu == FALSE && MENU_IsMenuActive())
4172 /* terminate the menu handling code */
4173 fEndMenu = TRUE;
4175 /* needs to be posted to wakeup the internal menu handler */
4176 /* which will now terminate the menu, in the event that */
4177 /* the main window was minimized, or lost focus, so we */
4178 /* don't end up with an orphaned menu */
4179 PostMessageA( pTopPopupWnd->hwndSelf, WM_CANCELMODE, 0, 0);
4184 /***********************************************************************
4185 * LookupMenuHandle (USER.217)
4187 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4189 HMENU hmenu32 = hmenu;
4190 UINT id32 = id;
4191 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4192 else return hmenu32;
4196 /**********************************************************************
4197 * LoadMenu16 (USER.150)
4199 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, SEGPTR name )
4201 HRSRC16 hRsrc;
4202 HGLOBAL16 handle;
4203 HMENU16 hMenu;
4205 if (HIWORD(name))
4207 char *str = (char *)PTR_SEG_TO_LIN( name );
4208 TRACE("(%04x,'%s')\n", instance, str );
4209 if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
4211 else
4212 TRACE("(%04x,%04x)\n",instance,LOWORD(name));
4214 if (!name) return 0;
4216 /* check for Win32 module */
4217 if (HIWORD(instance))
4218 return LoadMenuA(instance,PTR_SEG_TO_LIN(name));
4219 instance = GetExePtr( instance );
4221 if (!(hRsrc = FindResource16( instance, name, RT_MENU16 ))) return 0;
4222 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4223 hMenu = LoadMenuIndirect16(LockResource16(handle));
4224 FreeResource16( handle );
4225 return hMenu;
4229 /*****************************************************************
4230 * LoadMenuA (USER32.370)
4232 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4234 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4235 if (!hrsrc) return 0;
4236 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4240 /*****************************************************************
4241 * LoadMenuW (USER32.373)
4243 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4245 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4246 if (!hrsrc) return 0;
4247 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4251 /**********************************************************************
4252 * LoadMenuIndirect16 (USER.220)
4254 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4256 HMENU16 hMenu;
4257 WORD version, offset;
4258 LPCSTR p = (LPCSTR)template;
4260 TRACE("(%p)\n", template );
4261 version = GET_WORD(p);
4262 p += sizeof(WORD);
4263 if (version)
4265 WARN("version must be 0 for Win16\n" );
4266 return 0;
4268 offset = GET_WORD(p);
4269 p += sizeof(WORD) + offset;
4270 if (!(hMenu = CreateMenu())) return 0;
4271 if (!MENU_ParseResource( p, hMenu, FALSE ))
4273 DestroyMenu( hMenu );
4274 return 0;
4276 return hMenu;
4280 /**********************************************************************
4281 * LoadMenuIndirectA (USER32.371)
4283 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4285 HMENU16 hMenu;
4286 WORD version, offset;
4287 LPCSTR p = (LPCSTR)template;
4289 TRACE("%p\n", template );
4290 version = GET_WORD(p);
4291 p += sizeof(WORD);
4292 switch (version)
4294 case 0:
4295 offset = GET_WORD(p);
4296 p += sizeof(WORD) + offset;
4297 if (!(hMenu = CreateMenu())) return 0;
4298 if (!MENU_ParseResource( p, hMenu, TRUE ))
4300 DestroyMenu( hMenu );
4301 return 0;
4303 return hMenu;
4304 case 1:
4305 offset = GET_WORD(p);
4306 p += sizeof(WORD) + offset;
4307 if (!(hMenu = CreateMenu())) return 0;
4308 if (!MENUEX_ParseResource( p, hMenu))
4310 DestroyMenu( hMenu );
4311 return 0;
4313 return hMenu;
4314 default:
4315 ERR("version %d not supported.\n", version);
4316 return 0;
4321 /**********************************************************************
4322 * LoadMenuIndirectW (USER32.372)
4324 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4326 /* FIXME: is there anything different between A and W? */
4327 return LoadMenuIndirectA( template );
4331 /**********************************************************************
4332 * IsMenu16 (USER.358)
4334 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4336 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4337 return IS_A_MENU(menu);
4341 /**********************************************************************
4342 * IsMenu (USER32.346)
4344 BOOL WINAPI IsMenu(HMENU hmenu)
4346 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4347 return IS_A_MENU(menu);
4350 /**********************************************************************
4351 * GetMenuItemInfo_common
4354 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4355 LPMENUITEMINFOA lpmii, BOOL unicode)
4357 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4359 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4361 if (!menu)
4362 return FALSE;
4364 if (lpmii->fMask & MIIM_TYPE) {
4365 lpmii->fType = menu->fType;
4366 switch (MENU_ITEM_TYPE(menu->fType)) {
4367 case MF_STRING:
4368 if (menu->text) {
4369 int len = strlen(menu->text);
4370 if(lpmii->dwTypeData && lpmii->cch) {
4371 if (unicode)
4372 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4373 lpmii->cch);
4374 else
4375 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4376 /* if we've copied a substring we return its length */
4377 if(lpmii->cch <= len)
4378 lpmii->cch--;
4379 } else /* return length of string */
4380 lpmii->cch = len;
4382 break;
4383 case MF_OWNERDRAW:
4384 case MF_BITMAP:
4385 lpmii->dwTypeData = menu->text;
4386 /* fall through */
4387 default:
4388 lpmii->cch = 0;
4392 if (lpmii->fMask & MIIM_STRING) {
4393 if(lpmii->dwTypeData && lpmii->cch) {
4394 if (unicode)
4395 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4396 lpmii->cch);
4397 else
4398 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4400 lpmii->cch = strlen(menu->text);
4403 if (lpmii->fMask & MIIM_FTYPE)
4404 lpmii->fType = menu->fType;
4406 if (lpmii->fMask & MIIM_BITMAP)
4407 lpmii->hbmpItem = menu->hbmpItem;
4409 if (lpmii->fMask & MIIM_STATE)
4410 lpmii->fState = menu->fState;
4412 if (lpmii->fMask & MIIM_ID)
4413 lpmii->wID = menu->wID;
4415 if (lpmii->fMask & MIIM_SUBMENU)
4416 lpmii->hSubMenu = menu->hSubMenu;
4418 if (lpmii->fMask & MIIM_CHECKMARKS) {
4419 lpmii->hbmpChecked = menu->hCheckBit;
4420 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4422 if (lpmii->fMask & MIIM_DATA)
4423 lpmii->dwItemData = menu->dwItemData;
4425 return TRUE;
4428 /**********************************************************************
4429 * GetMenuItemInfoA (USER32.264)
4431 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4432 LPMENUITEMINFOA lpmii)
4434 return GetMenuItemInfo_common (hmenu, item, bypos, lpmii, FALSE);
4437 /**********************************************************************
4438 * GetMenuItemInfoW (USER32.265)
4440 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4441 LPMENUITEMINFOW lpmii)
4443 return GetMenuItemInfo_common (hmenu, item, bypos,
4444 (LPMENUITEMINFOA)lpmii, TRUE);
4447 /**********************************************************************
4448 * SetMenuItemInfo_common
4451 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4452 const MENUITEMINFOA *lpmii,
4453 BOOL unicode)
4455 if (!menu) return FALSE;
4457 if (lpmii->fMask & MIIM_TYPE ) {
4458 /* Get rid of old string. */
4459 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4460 HeapFree(SystemHeap, 0, menu->text);
4461 menu->text = NULL;
4464 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4465 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4466 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4468 menu->text = lpmii->dwTypeData;
4470 if (IS_STRING_ITEM(menu->fType) && menu->text) {
4471 if (unicode)
4472 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4473 else
4474 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4478 if (lpmii->fMask & MIIM_FTYPE ) {
4479 /* free the string when the type is changing */
4480 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4481 HeapFree(SystemHeap, 0, menu->text);
4482 menu->text = NULL;
4484 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4485 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4488 if (lpmii->fMask & MIIM_STRING ) {
4489 /* free the string when used */
4490 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4491 HeapFree(SystemHeap, 0, menu->text);
4492 if (unicode)
4493 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4494 else
4495 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4499 if (lpmii->fMask & MIIM_STATE)
4501 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4502 menu->fState = lpmii->fState;
4505 if (lpmii->fMask & MIIM_ID)
4506 menu->wID = lpmii->wID;
4508 if (lpmii->fMask & MIIM_SUBMENU) {
4509 menu->hSubMenu = lpmii->hSubMenu;
4510 if (menu->hSubMenu) {
4511 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4512 if (subMenu) {
4513 subMenu->wFlags |= MF_POPUP;
4514 menu->fType |= MF_POPUP;
4516 else
4517 /* FIXME: Return an error ? */
4518 menu->fType &= ~MF_POPUP;
4520 else
4521 menu->fType &= ~MF_POPUP;
4524 if (lpmii->fMask & MIIM_CHECKMARKS)
4526 if (lpmii->fType & MFT_RADIOCHECK)
4527 menu->fType |= MFT_RADIOCHECK;
4529 menu->hCheckBit = lpmii->hbmpChecked;
4530 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4532 if (lpmii->fMask & MIIM_DATA)
4533 menu->dwItemData = lpmii->dwItemData;
4535 debug_print_menuitem("SetMenuItemInfo_common: ", menu, "");
4536 return TRUE;
4539 /**********************************************************************
4540 * SetMenuItemInfoA (USER32.491)
4542 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4543 const MENUITEMINFOA *lpmii)
4545 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4546 lpmii, FALSE);
4549 /**********************************************************************
4550 * SetMenuItemInfoW (USER32.492)
4552 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4553 const MENUITEMINFOW *lpmii)
4555 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4556 (const MENUITEMINFOA*)lpmii, TRUE);
4559 /**********************************************************************
4560 * SetMenuDefaultItem (USER32.489)
4563 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4565 UINT i;
4566 POPUPMENU *menu;
4567 MENUITEM *item;
4569 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4571 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4573 /* reset all default-item flags */
4574 item = menu->items;
4575 for (i = 0; i < menu->nItems; i++, item++)
4577 item->fState &= ~MFS_DEFAULT;
4580 /* no default item */
4581 if ( -1 == uItem)
4583 return TRUE;
4586 item = menu->items;
4587 if ( bypos )
4589 if ( uItem >= menu->nItems ) return FALSE;
4590 item[uItem].fState |= MFS_DEFAULT;
4591 return TRUE;
4593 else
4595 for (i = 0; i < menu->nItems; i++, item++)
4597 if (item->wID == uItem)
4599 item->fState |= MFS_DEFAULT;
4600 return TRUE;
4605 return FALSE;
4608 /**********************************************************************
4609 * GetMenuDefaultItem (USER32.260)
4611 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4613 POPUPMENU *menu;
4614 MENUITEM * item;
4615 UINT i = 0;
4617 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4619 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4621 /* find default item */
4622 item = menu->items;
4624 /* empty menu */
4625 if (! item) return -1;
4627 while ( !( item->fState & MFS_DEFAULT ) )
4629 i++; item++;
4630 if (i >= menu->nItems ) return -1;
4633 /* default: don't return disabled items */
4634 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4636 /* search rekursiv when needed */
4637 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4639 UINT ret;
4640 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4641 if ( -1 != ret ) return ret;
4643 /* when item not found in submenu, return the popup item */
4645 return ( bypos ) ? i : item->wID;
4649 /*******************************************************************
4650 * InsertMenuItem16 (USER.441)
4652 * FIXME: untested
4654 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4655 const MENUITEMINFO16 *mii )
4657 MENUITEMINFOA miia;
4659 miia.cbSize = sizeof(miia);
4660 miia.fMask = mii->fMask;
4661 miia.dwTypeData = mii->dwTypeData;
4662 miia.fType = mii->fType;
4663 miia.fState = mii->fState;
4664 miia.wID = mii->wID;
4665 miia.hSubMenu = mii->hSubMenu;
4666 miia.hbmpChecked = mii->hbmpChecked;
4667 miia.hbmpUnchecked = mii->hbmpUnchecked;
4668 miia.dwItemData = mii->dwItemData;
4669 miia.cch = mii->cch;
4670 if (IS_STRING_ITEM(miia.fType))
4671 miia.dwTypeData = PTR_SEG_TO_LIN(miia.dwTypeData);
4672 return InsertMenuItemA( hmenu, pos, byposition, &miia );
4676 /**********************************************************************
4677 * InsertMenuItemA (USER32.323)
4679 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4680 const MENUITEMINFOA *lpmii)
4682 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4683 return SetMenuItemInfo_common(item, lpmii, FALSE);
4687 /**********************************************************************
4688 * InsertMenuItemW (USER32.324)
4690 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4691 const MENUITEMINFOW *lpmii)
4693 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4694 return SetMenuItemInfo_common(item, (const MENUITEMINFOA*)lpmii, TRUE);
4697 /**********************************************************************
4698 * CheckMenuRadioItem (USER32.47)
4701 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4702 UINT first, UINT last, UINT check,
4703 UINT bypos)
4705 MENUITEM *mifirst, *milast, *micheck;
4706 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4708 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4709 hMenu, first, last, check, bypos);
4711 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4712 milast = MENU_FindItem (&mlast, &last, bypos);
4713 micheck = MENU_FindItem (&mcheck, &check, bypos);
4715 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4716 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4717 micheck > milast || micheck < mifirst)
4718 return FALSE;
4720 while (mifirst <= milast)
4722 if (mifirst == micheck)
4724 mifirst->fType |= MFT_RADIOCHECK;
4725 mifirst->fState |= MFS_CHECKED;
4726 } else {
4727 mifirst->fType &= ~MFT_RADIOCHECK;
4728 mifirst->fState &= ~MFS_CHECKED;
4730 mifirst++;
4733 return TRUE;
4736 /**********************************************************************
4737 * CheckMenuRadioItem16 (not a Windows API)
4740 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4741 UINT16 first, UINT16 last, UINT16 check,
4742 BOOL16 bypos)
4744 return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4747 /**********************************************************************
4748 * GetMenuItemRect (USER32.266)
4750 * ATTENTION: Here, the returned values in rect are the screen
4751 * coordinates of the item just like if the menu was
4752 * always on the upper left side of the application.
4755 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4756 LPRECT rect)
4758 POPUPMENU *itemMenu;
4759 MENUITEM *item;
4760 HWND referenceHwnd;
4762 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4764 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4765 referenceHwnd = hwnd;
4767 if(!hwnd)
4769 itemMenu = MENU_GetMenu(hMenu);
4770 if (itemMenu == NULL)
4771 return FALSE;
4773 if(itemMenu->hWnd == 0)
4774 return FALSE;
4775 referenceHwnd = itemMenu->hWnd;
4778 if ((rect == NULL) || (item == NULL))
4779 return FALSE;
4781 *rect = item->rect;
4783 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4785 return TRUE;
4788 /**********************************************************************
4789 * GetMenuItemRect16 (USER.665)
4792 BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
4793 LPRECT16 rect)
4795 RECT r32;
4796 BOOL res;
4798 if (!rect) return FALSE;
4799 res = GetMenuItemRect (hwnd, hMenu, uItem, &r32);
4800 CONV_RECT32TO16 (&r32, rect);
4801 return res;
4804 /**********************************************************************
4805 * SetMenuInfo
4807 * FIXME
4808 * MIM_APPLYTOSUBMENUS
4809 * actually use the items to draw the menu
4811 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4813 POPUPMENU *menu;
4815 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4817 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4820 if (lpmi->fMask & MIM_BACKGROUND)
4821 menu->hbrBack = lpmi->hbrBack;
4823 if (lpmi->fMask & MIM_HELPID)
4824 menu->dwContextHelpID = lpmi->dwContextHelpID;
4826 if (lpmi->fMask & MIM_MAXHEIGHT)
4827 menu->cyMax = lpmi->cyMax;
4829 if (lpmi->fMask & MIM_MENUDATA)
4830 menu->dwMenuData = lpmi->dwMenuData;
4832 if (lpmi->fMask & MIM_STYLE)
4833 menu->dwStyle = lpmi->dwStyle;
4835 return TRUE;
4837 return FALSE;
4840 /**********************************************************************
4841 * GetMenuInfo
4843 * NOTES
4844 * win98/NT5.0
4847 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4848 { POPUPMENU *menu;
4850 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4852 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4855 if (lpmi->fMask & MIM_BACKGROUND)
4856 lpmi->hbrBack = menu->hbrBack;
4858 if (lpmi->fMask & MIM_HELPID)
4859 lpmi->dwContextHelpID = menu->dwContextHelpID;
4861 if (lpmi->fMask & MIM_MAXHEIGHT)
4862 lpmi->cyMax = menu->cyMax;
4864 if (lpmi->fMask & MIM_MENUDATA)
4865 lpmi->dwMenuData = menu->dwMenuData;
4867 if (lpmi->fMask & MIM_STYLE)
4868 lpmi->dwStyle = menu->dwStyle;
4870 return TRUE;
4872 return FALSE;
4875 /**********************************************************************
4876 * SetMenuContextHelpId16 (USER.384)
4878 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4880 return SetMenuContextHelpId( hMenu, dwContextHelpID );
4884 /**********************************************************************
4885 * SetMenuContextHelpId (USER32.488)
4887 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4889 LPPOPUPMENU menu;
4891 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4893 if ((menu = MENU_GetMenu(hMenu)))
4895 menu->dwContextHelpID = dwContextHelpID;
4896 return TRUE;
4898 return FALSE;
4901 /**********************************************************************
4902 * GetMenuContextHelpId16 (USER.385)
4904 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4906 return GetMenuContextHelpId( hMenu );
4909 /**********************************************************************
4910 * GetMenuContextHelpId (USER32.488)
4912 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4914 LPPOPUPMENU menu;
4916 TRACE("(0x%04x)\n", hMenu);
4918 if ((menu = MENU_GetMenu(hMenu)))
4920 return menu->dwContextHelpID;
4922 return 0;
4925 /**********************************************************************
4926 * MenuItemFromPoint (USER32.387)
4928 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4930 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4931 hWnd, hMenu, ptScreen.x, ptScreen.y);
4932 return 0;