StgOpenStorage16: correct arguments to the CreateFile call.
[wine.git] / controls / menu.c
blob5e1ad37132c337a75fca8ab9993c4a10cac044a8
1 /*
2 * Menu functions
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
7 */
9 /*
10 * Note: the style MF_MOUSESELECT is used to mark popup items that
11 * have been selected, i.e. their popup menu is currently displayed.
12 * This is probably not the meaning this style has in MS-Windows.
15 #include <assert.h>
16 #include <ctype.h>
17 #include <stdlib.h>
18 #include <string.h>
20 #include "windef.h"
21 #include "wingdi.h"
22 #include "wine/winbase16.h"
23 #include "wine/winuser16.h"
24 #include "win.h"
25 #include "task.h"
26 #include "heap.h"
27 #include "menu.h"
28 #include "nonclient.h"
29 #include "user.h"
30 #include "message.h"
31 #include "queue.h"
32 #include "tweak.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(menu)
39 /* internal popup menu window messages */
41 #define MM_SETMENUHANDLE (WM_USER + 0)
42 #define MM_GETMENUHANDLE (WM_USER + 1)
44 /* Menu item structure */
45 typedef struct {
46 /* ----------- MENUITEMINFO Stuff ----------- */
47 UINT fType; /* Item type. */
48 UINT fState; /* Item state. */
49 UINT wID; /* Item id. */
50 HMENU hSubMenu; /* Pop-up menu. */
51 HBITMAP hCheckBit; /* Bitmap when checked. */
52 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
53 LPSTR text; /* Item text or bitmap handle. */
54 DWORD dwItemData; /* Application defined. */
55 DWORD dwTypeData; /* depends on fMask */
56 HBITMAP hbmpItem; /* bitmap in win98 style menus */
57 /* ----------- Wine stuff ----------- */
58 RECT rect; /* Item area (relative to menu window) */
59 UINT xTab; /* X position of text after Tab */
60 } MENUITEM;
62 /* Popup menu structure */
63 typedef struct {
64 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
65 WORD wMagic; /* Magic number */
66 HQUEUE16 hTaskQ; /* Task queue for this menu */
67 WORD Width; /* Width of the whole menu */
68 WORD Height; /* Height of the whole menu */
69 WORD nItems; /* Number of items in the menu */
70 HWND hWnd; /* Window containing the menu */
71 MENUITEM *items; /* Array of menu items */
72 UINT FocusedItem; /* Currently focused item */
73 HWND hwndOwner; /* window receiving the messages for ownerdraw */
74 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
75 /* ------------ MENUINFO members ------ */
76 DWORD dwStyle; /* Extended mennu style */
77 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
78 HBRUSH hbrBack; /* brush for menu background */
79 DWORD dwContextHelpID;
80 DWORD dwMenuData; /* application defined value */
81 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
82 } POPUPMENU, *LPPOPUPMENU;
84 /* internal flags for menu tracking */
86 #define TF_ENDMENU 0x0001
87 #define TF_SUSPENDPOPUP 0x0002
88 #define TF_SKIPREMOVE 0x0004
90 typedef struct
92 UINT trackFlags;
93 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
94 HMENU hTopMenu; /* initial menu */
95 HWND hOwnerWnd; /* where notifications are sent */
96 POINT pt;
97 } MTRACKER;
99 #define MENU_MAGIC 0x554d /* 'MU' */
100 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
102 #define ITEM_PREV -1
103 #define ITEM_NEXT 1
105 /* Internal MENU_TrackMenu() flags */
106 #define TPM_INTERNAL 0xF0000000
107 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
108 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
109 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
111 /* popup menu shade thickness */
112 #define POPUP_XSHADE 4
113 #define POPUP_YSHADE 4
115 /* Space between 2 menu bar items */
116 #define MENU_BAR_ITEMS_SPACE 12
118 /* Minimum width of a tab character */
119 #define MENU_TAB_SPACE 8
121 /* Height of a separator item */
122 #define SEPARATOR_HEIGHT 5
124 /* (other menu->FocusedItem values give the position of the focused item) */
125 #define NO_SELECTED_ITEM 0xffff
127 #define MENU_ITEM_TYPE(flags) \
128 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
130 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
131 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
133 #define IS_SYSTEM_MENU(menu) \
134 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
136 #define IS_SYSTEM_POPUP(menu) \
137 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
139 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
140 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
141 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
142 MF_POPUP | MF_SYSMENU | MF_HELP)
143 #define STATE_MASK (~TYPE_MASK)
145 /* Dimension of the menu bitmaps */
146 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
147 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
149 static HBITMAP hStdRadioCheck = 0;
150 static HBITMAP hStdCheck = 0;
151 static HBITMAP hStdMnArrow = 0;
153 /* Minimze/restore/close buttons to be inserted in menubar */
154 static HBITMAP hBmpMinimize = 0;
155 static HBITMAP hBmpMinimizeD = 0;
156 static HBITMAP hBmpMaximize = 0;
157 static HBITMAP hBmpMaximizeD = 0;
158 static HBITMAP hBmpClose = 0;
159 static HBITMAP hBmpCloseD = 0;
162 static HBRUSH hShadeBrush = 0;
163 static HFONT hMenuFont = 0;
164 static HFONT hMenuFontBold = 0;
166 static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
168 /* Use global popup window because there's no way 2 menus can
169 * be tracked at the same time. */
171 static WND* pTopPopupWnd = 0;
172 static UINT uSubPWndLevel = 0;
174 /* Flag set by EndMenu() to force an exit from menu tracking */
175 static BOOL fEndMenu = FALSE;
178 /***********************************************************************
179 * debug_print_menuitem
181 * Print a menuitem in readable form.
184 #define debug_print_menuitem(pre, mp, post) \
185 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
187 #define MENUOUT(text) \
188 DPRINTF("%s%s", (count++ ? "," : ""), (text))
190 #define MENUFLAG(bit,text) \
191 do { \
192 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
193 } while (0)
195 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
196 const char *postfix)
198 TRACE("%s ", prefix);
199 if (mp) {
200 UINT flags = mp->fType;
201 int typ = MENU_ITEM_TYPE(flags);
202 DPRINTF( "{ ID=0x%x", mp->wID);
203 if (flags & MF_POPUP)
204 DPRINTF( ", Sub=0x%x", mp->hSubMenu);
205 if (flags) {
206 int count = 0;
207 DPRINTF( ", Typ=");
208 if (typ == MFT_STRING)
209 /* Nothing */ ;
210 else if (typ == MFT_SEPARATOR)
211 MENUOUT("sep");
212 else if (typ == MFT_OWNERDRAW)
213 MENUOUT("own");
214 else if (typ == MFT_BITMAP)
215 MENUOUT("bit");
216 else
217 MENUOUT("???");
218 flags -= typ;
220 MENUFLAG(MF_POPUP, "pop");
221 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
222 MENUFLAG(MFT_MENUBREAK, "brk");
223 MENUFLAG(MFT_RADIOCHECK, "radio");
224 MENUFLAG(MFT_RIGHTORDER, "rorder");
225 MENUFLAG(MF_SYSMENU, "sys");
226 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
228 if (flags)
229 DPRINTF( "+0x%x", flags);
231 flags = mp->fState;
232 if (flags) {
233 int count = 0;
234 DPRINTF( ", State=");
235 MENUFLAG(MFS_GRAYED, "grey");
236 MENUFLAG(MFS_DEFAULT, "default");
237 MENUFLAG(MFS_DISABLED, "dis");
238 MENUFLAG(MFS_CHECKED, "check");
239 MENUFLAG(MFS_HILITE, "hi");
240 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
241 MENUFLAG(MF_MOUSESELECT, "mouse");
242 if (flags)
243 DPRINTF( "+0x%x", flags);
245 if (mp->hCheckBit)
246 DPRINTF( ", Chk=0x%x", mp->hCheckBit);
247 if (mp->hUnCheckBit)
248 DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
250 if (typ == MFT_STRING) {
251 if (mp->text)
252 DPRINTF( ", Text=\"%s\"", mp->text);
253 else
254 DPRINTF( ", Text=Null");
255 } else if (mp->text == NULL)
256 /* Nothing */ ;
257 else
258 DPRINTF( ", Text=%p", mp->text);
259 if (mp->dwItemData)
260 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
261 DPRINTF( " }");
262 } else {
263 DPRINTF( "NULL");
266 DPRINTF(" %s\n", postfix);
269 #undef MENUOUT
270 #undef MENUFLAG
273 /***********************************************************************
274 * MENU_GetMenu
276 * Validate the given menu handle and returns the menu structure pointer.
278 POPUPMENU *MENU_GetMenu(HMENU hMenu)
280 POPUPMENU *menu;
281 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
282 if (!IS_A_MENU(menu))
284 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
285 menu = NULL;
287 return menu;
290 /***********************************************************************
291 * MENU_CopySysPopup
293 * Return the default system menu.
295 static HMENU MENU_CopySysPopup(void)
297 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
299 if( hMenu ) {
300 POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
301 menu->wFlags |= MF_SYSMENU | MF_POPUP;
302 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
304 else {
305 hMenu = 0;
306 ERR("Unable to load default system menu\n" );
309 TRACE("returning %x.\n", hMenu );
311 return hMenu;
314 /***********************************************************************
315 * MENU_GetTopPopupWnd()
317 * Return the locked pointer pTopPopupWnd.
319 static WND *MENU_GetTopPopupWnd()
321 return WIN_LockWndPtr(pTopPopupWnd);
323 /***********************************************************************
324 * MENU_ReleaseTopPopupWnd()
326 * Realease the locked pointer pTopPopupWnd.
328 static void MENU_ReleaseTopPopupWnd()
330 WIN_ReleaseWndPtr(pTopPopupWnd);
332 /***********************************************************************
333 * MENU_DestroyTopPopupWnd()
335 * Destroy the locked pointer pTopPopupWnd.
337 static void MENU_DestroyTopPopupWnd()
339 WND *tmpWnd = pTopPopupWnd;
340 pTopPopupWnd = NULL;
341 WIN_ReleaseWndPtr(tmpWnd);
346 /**********************************************************************
347 * MENU_GetSysMenu
349 * Create a copy of the system menu. System menu in Windows is
350 * a special menu-bar with the single entry - system menu popup.
351 * This popup is presented to the outside world as a "system menu".
352 * However, the real system menu handle is sometimes seen in the
353 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
355 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
357 HMENU hMenu;
359 if ((hMenu = CreateMenu()))
361 POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
362 menu->wFlags = MF_SYSMENU;
363 menu->hWnd = hWnd;
365 if (hPopupMenu == (HMENU)(-1))
366 hPopupMenu = MENU_CopySysPopup();
367 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
369 if (hPopupMenu)
371 InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
373 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
374 menu->items[0].fState = 0;
375 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
376 menu->wFlags |= MF_SYSMENU;
378 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
379 return hMenu;
381 DestroyMenu( hMenu );
383 ERR("failed to load system menu!\n");
384 return 0;
388 /***********************************************************************
389 * MENU_Init
391 * Menus initialisation.
393 BOOL MENU_Init()
395 HBITMAP hBitmap;
396 NONCLIENTMETRICSA ncm;
398 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
399 0x55, 0, 0xAA, 0,
400 0x55, 0, 0xAA, 0,
401 0x55, 0, 0xAA, 0 };
403 /* Load menu bitmaps */
404 hStdCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK));
405 hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK));
406 hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
407 /* Load system buttons bitmaps */
408 hBmpMinimize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE));
409 hBmpMinimizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED));
410 hBmpMaximize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE));
411 hBmpMaximizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED));
412 hBmpClose = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE));
413 hBmpCloseD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED));
415 if (hStdCheck)
417 BITMAP bm;
418 GetObjectA( hStdCheck, sizeof(bm), &bm );
419 check_bitmap_width = bm.bmWidth;
420 check_bitmap_height = bm.bmHeight;
421 } else
422 return FALSE;
424 /* Assume that radio checks have the same size as regular check. */
425 if (!hStdRadioCheck)
426 return FALSE;
428 if (hStdMnArrow)
430 BITMAP bm;
431 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
432 arrow_bitmap_width = bm.bmWidth;
433 arrow_bitmap_height = bm.bmHeight;
434 } else
435 return FALSE;
437 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
438 return FALSE;
440 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
441 return FALSE;
443 DeleteObject( hBitmap );
444 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
445 return FALSE;
447 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
448 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
449 return FALSE;
451 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
452 return FALSE;
454 ncm.lfMenuFont.lfWeight += 300;
455 if ( ncm.lfMenuFont.lfWeight > 1000)
456 ncm.lfMenuFont.lfWeight = 1000;
458 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
459 return FALSE;
461 return TRUE;
464 /***********************************************************************
465 * MENU_InitSysMenuPopup
467 * Grey the appropriate items in System menu.
469 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
471 BOOL gray;
473 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
474 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
475 gray = ((style & WS_MAXIMIZE) != 0);
476 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
477 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
478 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
479 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
480 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
481 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
482 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
483 gray = (clsStyle & CS_NOCLOSE) != 0;
485 /* The menu item must keep its state if it's disabled */
486 if(gray)
487 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
491 /******************************************************************************
493 * UINT MENU_GetStartOfNextColumn(
494 * HMENU hMenu )
496 *****************************************************************************/
498 static UINT MENU_GetStartOfNextColumn(
499 HMENU hMenu )
501 POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
502 UINT i = menu->FocusedItem + 1;
504 if(!menu)
505 return NO_SELECTED_ITEM;
507 if( i == NO_SELECTED_ITEM )
508 return i;
510 for( ; i < menu->nItems; ++i ) {
511 if (menu->items[i].fType & MF_MENUBARBREAK)
512 return i;
515 return NO_SELECTED_ITEM;
519 /******************************************************************************
521 * UINT MENU_GetStartOfPrevColumn(
522 * HMENU hMenu )
524 *****************************************************************************/
526 static UINT MENU_GetStartOfPrevColumn(
527 HMENU hMenu )
529 POPUPMENU const *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
530 UINT i;
532 if( !menu )
533 return NO_SELECTED_ITEM;
535 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
536 return NO_SELECTED_ITEM;
538 /* Find the start of the column */
540 for(i = menu->FocusedItem; i != 0 &&
541 !(menu->items[i].fType & MF_MENUBARBREAK);
542 --i); /* empty */
544 if(i == 0)
545 return NO_SELECTED_ITEM;
547 for(--i; i != 0; --i) {
548 if (menu->items[i].fType & MF_MENUBARBREAK)
549 break;
552 TRACE("ret %d.\n", i );
554 return i;
559 /***********************************************************************
560 * MENU_FindItem
562 * Find a menu item. Return a pointer on the item, and modifies *hmenu
563 * in case the item was in a sub-menu.
565 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
567 POPUPMENU *menu;
568 UINT i;
570 if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
571 if (wFlags & MF_BYPOSITION)
573 if (*nPos >= menu->nItems) return NULL;
574 return &menu->items[*nPos];
576 else
578 MENUITEM *item = menu->items;
579 for (i = 0; i < menu->nItems; i++, item++)
581 if (item->wID == *nPos)
583 *nPos = i;
584 return item;
586 else if (item->fType & MF_POPUP)
588 HMENU hsubmenu = item->hSubMenu;
589 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
590 if (subitem)
592 *hmenu = hsubmenu;
593 return subitem;
598 return NULL;
601 /***********************************************************************
602 * MENU_FindSubMenu
604 * Find a Sub menu. Return the position of the submenu, and modifies
605 * *hmenu in case it is found in another sub-menu.
606 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
608 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
610 POPUPMENU *menu;
611 UINT i;
612 MENUITEM *item;
613 if (((*hmenu)==0xffff) ||
614 (!(menu = MENU_GetMenu(*hmenu))))
615 return NO_SELECTED_ITEM;
616 item = menu->items;
617 for (i = 0; i < menu->nItems; i++, item++) {
618 if(!(item->fType & MF_POPUP)) continue;
619 if (item->hSubMenu == hSubTarget) {
620 return i;
622 else {
623 HMENU hsubmenu = item->hSubMenu;
624 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
625 if (pos != NO_SELECTED_ITEM) {
626 *hmenu = hsubmenu;
627 return pos;
631 return NO_SELECTED_ITEM;
634 /***********************************************************************
635 * MENU_FreeItemData
637 static void MENU_FreeItemData( MENUITEM* item )
639 /* delete text */
640 if (IS_STRING_ITEM(item->fType) && item->text)
641 HeapFree( SystemHeap, 0, item->text );
644 /***********************************************************************
645 * MENU_FindItemByCoords
647 * Find the item at the specified coordinates (screen coords). Does
648 * not work for child windows and therefore should not be called for
649 * an arbitrary system menu.
651 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
652 POINT pt, UINT *pos )
654 MENUITEM *item;
655 UINT i;
656 RECT wrect;
658 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
659 pt.x -= wrect.left;pt.y -= wrect.top;
660 item = menu->items;
661 for (i = 0; i < menu->nItems; i++, item++)
663 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
664 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
666 if (pos) *pos = i;
667 return item;
670 return NULL;
674 /***********************************************************************
675 * MENU_FindItemByKey
677 * Find the menu item selected by a key press.
678 * Return item id, -1 if none, -2 if we should close the menu.
680 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
681 UINT key, BOOL forceMenuChar )
683 TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
685 if (!IsMenu( hmenu ))
687 WND* w = WIN_FindWndPtr(hwndOwner);
688 hmenu = GetSubMenu(w->hSysMenu, 0);
689 WIN_ReleaseWndPtr(w);
692 if (hmenu)
694 POPUPMENU *menu = MENU_GetMenu( hmenu );
695 MENUITEM *item = menu->items;
696 LONG menuchar;
698 if( !forceMenuChar )
700 UINT i;
702 key = toupper(key);
703 for (i = 0; i < menu->nItems; i++, item++)
705 if (item->text && (IS_STRING_ITEM(item->fType)))
707 char *p = item->text - 2;
710 p = strchr (p + 2, '&');
712 while (p != NULL && p [1] == '&');
713 if (p && (toupper(p[1]) == key)) return i;
717 menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
718 MAKEWPARAM( key, menu->wFlags ), hmenu );
719 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
720 if (HIWORD(menuchar) == 1) return (UINT)(-2);
722 return (UINT)(-1);
724 /***********************************************************************
725 * MENU_LoadMagicItem
727 * Load the bitmap associated with the magic menu item and its style
730 static HBITMAP MENU_LoadMagicItem(UINT id, BOOL hilite, DWORD dwItemData)
733 * Magic menu item id's section
734 * These magic id's are used by windows to insert "standard" mdi
735 * buttons (minimize,restore,close) on menu. Under windows,
736 * these magic id's make sure the right things appear when those
737 * bitmap buttons are pressed/selected/released.
740 switch(id & 0xffff)
741 { case HBMMENU_SYSTEM:
742 return (dwItemData) ?
743 (HBITMAP)dwItemData :
744 (hilite ? hBmpMinimizeD : hBmpMinimize);
745 case HBMMENU_MBAR_RESTORE:
746 return (hilite ? hBmpMaximizeD: hBmpMaximize);
747 case HBMMENU_MBAR_MINIMIZE:
748 return (hilite ? hBmpMinimizeD : hBmpMinimize);
749 case HBMMENU_MBAR_CLOSE:
750 return (hilite ? hBmpCloseD : hBmpClose);
751 case HBMMENU_CALLBACK:
752 case HBMMENU_MBAR_CLOSE_D:
753 case HBMMENU_MBAR_MINIMIZE_D:
754 case HBMMENU_POPUP_CLOSE:
755 case HBMMENU_POPUP_RESTORE:
756 case HBMMENU_POPUP_MAXIMIZE:
757 case HBMMENU_POPUP_MINIMIZE:
758 default:
759 FIXME("Magic 0x%08x not implemented\n", id);
760 return 0;
765 /***********************************************************************
766 * MENU_CalcItemSize
768 * Calculate the size of the menu item and store it in lpitem->rect.
770 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
771 INT orgX, INT orgY, BOOL menuBar )
773 char *p;
775 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
776 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
777 (menuBar ? " (MenuBar)" : ""));
779 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
781 if (lpitem->fType & MF_OWNERDRAW)
784 ** Experimentation under Windows reveals that an owner-drawn
785 ** menu is expected to return the size of the content part of
786 ** the menu item, not including the checkmark nor the submenu
787 ** arrow. Windows adds those values itself and returns the
788 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
790 MEASUREITEMSTRUCT mis;
791 mis.CtlType = ODT_MENU;
792 mis.CtlID = 0;
793 mis.itemID = lpitem->wID;
794 mis.itemData = (DWORD)lpitem->dwItemData;
795 mis.itemHeight = 0;
796 mis.itemWidth = 0;
797 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
798 lpitem->rect.right += mis.itemWidth;
800 if (menuBar)
802 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
805 /* under at least win95 you seem to be given a standard
806 height for the menu and the height value is ignored */
808 if (TWEAK_WineLook == WIN31_LOOK)
809 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
810 else
811 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
813 else
814 lpitem->rect.bottom += mis.itemHeight;
816 TRACE("id=%04x size=%dx%d\n",
817 lpitem->wID, mis.itemWidth, mis.itemHeight);
818 /* Fall through to get check/arrow width calculation. */
821 if (lpitem->fType & MF_SEPARATOR)
823 lpitem->rect.bottom += SEPARATOR_HEIGHT;
824 return;
827 if (!menuBar)
829 lpitem->rect.right += 2 * check_bitmap_width;
830 if (lpitem->fType & MF_POPUP)
831 lpitem->rect.right += arrow_bitmap_width;
834 if (lpitem->fType & MF_OWNERDRAW)
835 return;
837 if (IS_BITMAP_ITEM(lpitem->fType))
839 BITMAP bm;
840 HBITMAP resBmp = 0;
842 /* Check if there is a magic menu item associated with this item */
843 if((LOWORD((int)lpitem->text))<12)
845 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fType & MF_HILITE),
846 lpitem->dwItemData);
848 else
849 resBmp = (HBITMAP)lpitem->text;
851 if (GetObjectA(resBmp, sizeof(bm), &bm ))
853 lpitem->rect.right += bm.bmWidth;
854 lpitem->rect.bottom += bm.bmHeight;
860 /* If we get here, then it must be a text item */
861 if (IS_STRING_ITEM( lpitem->fType ))
862 { SIZE size;
864 GetTextExtentPoint32A(hdc, lpitem->text, strlen(lpitem->text), &size);
866 lpitem->rect.right += size.cx;
867 if (TWEAK_WineLook == WIN31_LOOK)
868 lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
869 else
870 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
871 lpitem->xTab = 0;
873 if (menuBar)
875 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
877 else if ((p = strchr( lpitem->text, '\t' )) != NULL)
879 /* Item contains a tab (only meaningful in popup menus) */
880 GetTextExtentPoint32A(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
881 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
882 lpitem->rect.right += MENU_TAB_SPACE;
884 else
886 if (strchr( lpitem->text, '\b' ))
887 lpitem->rect.right += MENU_TAB_SPACE;
888 lpitem->xTab = lpitem->rect.right - check_bitmap_width
889 - arrow_bitmap_width;
892 TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
896 /***********************************************************************
897 * MENU_PopupMenuCalcSize
899 * Calculate the size of a popup menu.
901 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
903 MENUITEM *lpitem;
904 HDC hdc;
905 int start, i;
906 int orgX, orgY, maxX, maxTab, maxTabWidth;
908 lppop->Width = lppop->Height = 0;
909 if (lppop->nItems == 0) return;
910 hdc = GetDC( 0 );
912 SelectObject( hdc, hMenuFont);
914 start = 0;
915 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2 ;
917 while (start < lppop->nItems)
919 lpitem = &lppop->items[start];
920 orgX = maxX;
921 orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
923 maxTab = maxTabWidth = 0;
925 /* Parse items until column break or end of menu */
926 for (i = start; i < lppop->nItems; i++, lpitem++)
928 if ((i != start) &&
929 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
931 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
933 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
934 maxX = max( maxX, lpitem->rect.right );
935 orgY = lpitem->rect.bottom;
936 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
938 maxTab = max( maxTab, lpitem->xTab );
939 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
943 /* Finish the column (set all items to the largest width found) */
944 maxX = max( maxX, maxTab + maxTabWidth );
945 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
947 lpitem->rect.right = maxX;
948 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
949 lpitem->xTab = maxTab;
952 lppop->Height = max( lppop->Height, orgY );
955 lppop->Width = maxX;
957 /* space for 3d border */
958 if(TWEAK_WineLook > WIN31_LOOK)
960 lppop->Height += 2;
961 lppop->Width += 2;
964 ReleaseDC( 0, hdc );
968 /***********************************************************************
969 * MENU_MenuBarCalcSize
971 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
972 * height is off by 1 pixel which causes lengthy window relocations when
973 * active document window is maximized/restored.
975 * Calculate the size of the menu bar.
977 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
978 LPPOPUPMENU lppop, HWND hwndOwner )
980 MENUITEM *lpitem;
981 int start, i, orgX, orgY, maxY, helpPos;
983 if ((lprect == NULL) || (lppop == NULL)) return;
984 if (lppop->nItems == 0) return;
985 TRACE("left=%d top=%d right=%d bottom=%d\n",
986 lprect->left, lprect->top, lprect->right, lprect->bottom);
987 lppop->Width = lprect->right - lprect->left;
988 lppop->Height = 0;
989 maxY = lprect->top;
990 start = 0;
991 helpPos = -1;
992 while (start < lppop->nItems)
994 lpitem = &lppop->items[start];
995 orgX = lprect->left;
996 orgY = maxY;
998 /* Parse items until line break or end of menu */
999 for (i = start; i < lppop->nItems; i++, lpitem++)
1001 if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i;
1002 if ((i != start) &&
1003 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1005 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1006 orgX, orgY );
1007 debug_print_menuitem (" item: ", lpitem, "");
1008 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1010 if (lpitem->rect.right > lprect->right)
1012 if (i != start) break;
1013 else lpitem->rect.right = lprect->right;
1015 maxY = max( maxY, lpitem->rect.bottom );
1016 orgX = lpitem->rect.right;
1019 /* Finish the line (set all items to the largest height found) */
1020 while (start < i) lppop->items[start++].rect.bottom = maxY;
1023 lprect->bottom = maxY;
1024 lppop->Height = lprect->bottom - lprect->top;
1026 /* Flush right all magic items and items between the MF_HELP and */
1027 /* the last item (if several lines, only move the last line) */
1028 lpitem = &lppop->items[lppop->nItems-1];
1029 orgY = lpitem->rect.top;
1030 orgX = lprect->right;
1031 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
1033 if ( !IS_BITMAP_ITEM(lpitem->fType) && ((helpPos ==-1) ? TRUE : (helpPos>i) ))
1034 break; /* done */
1035 if (lpitem->rect.top != orgY) break; /* Other line */
1036 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1037 lpitem->rect.left += orgX - lpitem->rect.right;
1038 lpitem->rect.right = orgX;
1039 orgX = lpitem->rect.left;
1043 /***********************************************************************
1044 * MENU_DrawMenuItem
1046 * Draw a single menu item.
1048 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1049 UINT height, BOOL menuBar, UINT odaction )
1051 RECT rect;
1053 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1055 if (lpitem->fType & MF_SYSMENU)
1057 if( !IsIconic(hwnd) ) {
1058 if (TWEAK_WineLook > WIN31_LOOK)
1059 NC_DrawSysButton95( hwnd, hdc,
1060 lpitem->fState &
1061 (MF_HILITE | MF_MOUSESELECT) );
1062 else
1063 NC_DrawSysButton( hwnd, hdc,
1064 lpitem->fState &
1065 (MF_HILITE | MF_MOUSESELECT) );
1068 return;
1071 if (lpitem->fType & MF_OWNERDRAW)
1074 ** Experimentation under Windows reveals that an owner-drawn
1075 ** menu is given the rectangle which includes the space it requested
1076 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1077 ** and a popup-menu arrow. This is the value of lpitem->rect.
1078 ** Windows will leave all drawing to the application except for
1079 ** the popup-menu arrow. Windows always draws that itself, after
1080 ** the menu owner has finished drawing.
1082 DRAWITEMSTRUCT dis;
1084 dis.CtlType = ODT_MENU;
1085 dis.CtlID = 0;
1086 dis.itemID = lpitem->wID;
1087 dis.itemData = (DWORD)lpitem->dwItemData;
1088 dis.itemState = 0;
1089 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1090 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED;
1091 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1092 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1093 dis.hwndItem = hmenu;
1094 dis.hDC = hdc;
1095 dis.rcItem = lpitem->rect;
1096 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1097 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
1098 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1099 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1100 dis.rcItem.bottom);
1101 SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1102 /* Fall through to draw popup-menu arrow */
1105 TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
1106 lpitem->rect.right,lpitem->rect.bottom);
1108 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1110 rect = lpitem->rect;
1112 if (!(lpitem->fType & MF_OWNERDRAW))
1114 if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)))
1115 if ((menuBar) && (TWEAK_WineLook==WIN98_LOOK))
1116 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1117 else
1118 FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
1119 else
1120 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1123 SetBkMode( hdc, TRANSPARENT );
1125 if (!(lpitem->fType & MF_OWNERDRAW))
1127 /* vertical separator */
1128 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1130 if (TWEAK_WineLook > WIN31_LOOK)
1132 RECT rc = rect;
1133 rc.top = 3;
1134 rc.bottom = height - 3;
1135 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1137 else
1139 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1140 MoveTo16( hdc, rect.left, 0 );
1141 LineTo( hdc, rect.left, height );
1145 /* horizontal separator */
1146 if (lpitem->fType & MF_SEPARATOR)
1148 if (TWEAK_WineLook > WIN31_LOOK)
1150 RECT rc = rect;
1151 rc.left++;
1152 rc.right--;
1153 rc.top += SEPARATOR_HEIGHT / 2;
1154 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1156 else
1158 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1159 MoveTo16( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
1160 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1162 return;
1166 /* Setup colors */
1168 if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)) )
1170 if (lpitem->fState & MF_GRAYED)
1171 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1172 else
1173 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
1174 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
1176 else
1178 if (lpitem->fState & MF_GRAYED)
1179 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1180 else
1181 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1182 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1185 /* helper lines for debugging */
1186 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1187 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1188 MoveTo16( hdc, rect.left, (rect.top + rect.bottom)/2 );
1189 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1192 if (!menuBar)
1194 INT y = rect.top + rect.bottom;
1196 if (!(lpitem->fType & MF_OWNERDRAW))
1198 /* Draw the check mark
1200 * FIXME:
1201 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1204 if (lpitem->fState & MF_CHECKED)
1206 HBITMAP bm = lpitem->hCheckBit ? lpitem->hCheckBit :
1207 ((lpitem->fType & MFT_RADIOCHECK) ? hStdRadioCheck : hStdCheck);
1208 HDC hdcMem = CreateCompatibleDC( hdc );
1210 SelectObject( hdcMem, bm );
1211 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1212 check_bitmap_width, check_bitmap_height,
1213 hdcMem, 0, 0, SRCCOPY );
1214 DeleteDC( hdcMem );
1216 else if (lpitem->hUnCheckBit)
1218 HDC hdcMem = CreateCompatibleDC( hdc );
1220 SelectObject( hdcMem, lpitem->hUnCheckBit );
1221 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1222 check_bitmap_width, check_bitmap_height,
1223 hdcMem, 0, 0, SRCCOPY );
1224 DeleteDC( hdcMem );
1228 /* Draw the popup-menu arrow */
1229 if (lpitem->fType & MF_POPUP)
1231 HDC hdcMem = CreateCompatibleDC( hdc );
1232 HBITMAP hOrigBitmap;
1234 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1235 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1236 (y - arrow_bitmap_height) / 2,
1237 arrow_bitmap_width, arrow_bitmap_height,
1238 hdcMem, 0, 0, SRCCOPY );
1239 SelectObject( hdcMem, hOrigBitmap );
1240 DeleteDC( hdcMem );
1243 rect.left += check_bitmap_width;
1244 rect.right -= arrow_bitmap_width;
1247 /* Done for owner-drawn */
1248 if (lpitem->fType & MF_OWNERDRAW)
1249 return;
1251 /* Draw the item text or bitmap */
1252 if (IS_BITMAP_ITEM(lpitem->fType))
1253 { int top;
1255 HBITMAP resBmp = 0;
1257 HDC hdcMem = CreateCompatibleDC( hdc );
1260 * Check if there is a magic menu item associated with this item
1261 * and load the appropriate bitmap
1263 if((LOWORD((int)lpitem->text)) < 12)
1265 resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fState & MF_HILITE),
1266 lpitem->dwItemData);
1268 else
1269 resBmp = (HBITMAP)lpitem->text;
1271 if (resBmp)
1273 BITMAP bm;
1274 GetObjectA( resBmp, sizeof(bm), &bm );
1276 SelectObject(hdcMem,resBmp );
1278 /* handle fontsize > bitmap_height */
1279 top = ((rect.bottom-rect.top)>bm.bmHeight) ?
1280 rect.top+(rect.bottom-rect.top-bm.bmHeight)/2 : rect.top;
1282 BitBlt( hdc, rect.left, top, rect.right - rect.left,
1283 rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY );
1285 DeleteDC( hdcMem );
1287 return;
1290 /* No bitmap - process text if present */
1291 else if (IS_STRING_ITEM(lpitem->fType))
1293 register int i;
1294 HFONT hfontOld = 0;
1296 UINT uFormat = (menuBar) ?
1297 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1298 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1300 if ( lpitem->fState & MFS_DEFAULT )
1302 hfontOld = SelectObject( hdc, hMenuFontBold);
1305 if (menuBar)
1307 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1308 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1309 i = strlen( lpitem->text );
1311 else
1313 for (i = 0; lpitem->text[i]; i++)
1314 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1315 break;
1318 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1320 if (!(lpitem->fState & MF_HILITE) )
1322 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1323 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1324 DrawTextA( hdc, lpitem->text, i, &rect, uFormat );
1325 --rect.left; --rect.top; --rect.right; --rect.bottom;
1327 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1330 DrawTextA( hdc, lpitem->text, i, &rect, uFormat);
1332 /* paint the shortcut text */
1333 if (lpitem->text[i]) /* There's a tab or flush-right char */
1335 if (lpitem->text[i] == '\t')
1337 rect.left = lpitem->xTab;
1338 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1340 else
1342 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1345 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1347 if (!(lpitem->fState & MF_HILITE) )
1349 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1350 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1351 DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1352 --rect.left; --rect.top; --rect.right; --rect.bottom;
1354 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1356 DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1359 if (hfontOld)
1360 SelectObject (hdc, hfontOld);
1365 /***********************************************************************
1366 * MENU_DrawPopupMenu
1368 * Paint a popup menu.
1370 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1372 HBRUSH hPrevBrush = 0;
1373 RECT rect;
1375 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1377 GetClientRect( hwnd, &rect );
1379 if(TWEAK_WineLook == WIN31_LOOK)
1381 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1382 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1385 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1386 && (SelectObject( hdc, hMenuFont)))
1388 HPEN hPrevPen;
1390 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1392 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1393 if( hPrevPen )
1395 INT ropPrev, i;
1396 POPUPMENU *menu;
1398 /* draw 3-d shade */
1399 if(TWEAK_WineLook == WIN31_LOOK) {
1400 SelectObject( hdc, hShadeBrush );
1401 SetBkMode( hdc, TRANSPARENT );
1402 ropPrev = SetROP2( hdc, R2_MASKPEN );
1404 i = rect.right; /* why SetBrushOrg() doesn't? */
1405 PatBlt( hdc, i & 0xfffffffe,
1406 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1407 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1408 rect.bottom - rect.top, 0x00a000c9 );
1409 i = rect.bottom;
1410 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1411 i & 0xfffffffe,rect.right - rect.left,
1412 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1413 SelectObject( hdc, hPrevPen );
1414 SelectObject( hdc, hPrevBrush );
1415 SetROP2( hdc, ropPrev );
1417 else
1418 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1420 /* draw menu items */
1422 menu = MENU_GetMenu( hmenu );
1423 if (menu && menu->nItems)
1425 MENUITEM *item;
1426 UINT u;
1428 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1429 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1430 menu->Height, FALSE, ODA_DRAWENTIRE );
1433 } else
1435 SelectObject( hdc, hPrevBrush );
1440 /***********************************************************************
1441 * MENU_DrawMenuBar
1443 * Paint a menu bar. Returns the height of the menu bar.
1444 * called from [windows/nonclient.c]
1446 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1447 BOOL suppress_draw)
1449 LPPOPUPMENU lppop;
1450 UINT i,retvalue;
1451 HFONT hfontOld = 0;
1453 WND *wndPtr = WIN_FindWndPtr( hwnd );
1455 lppop = MENU_GetMenu ((HMENU)wndPtr->wIDmenu );
1456 if (lppop == NULL || lprect == NULL)
1458 retvalue = GetSystemMetrics(SM_CYMENU);
1459 goto END;
1462 TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1464 hfontOld = SelectObject( hDC, hMenuFont);
1466 if (lppop->Height == 0)
1467 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1469 lprect->bottom = lprect->top + lppop->Height;
1471 if (suppress_draw)
1473 retvalue = lppop->Height;
1474 goto END;
1477 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1479 if (TWEAK_WineLook == WIN31_LOOK)
1481 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1482 MoveTo16( hDC, lprect->left, lprect->bottom );
1483 LineTo( hDC, lprect->right, lprect->bottom );
1485 else
1487 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1488 MoveTo16( hDC, lprect->left, lprect->bottom );
1489 LineTo( hDC, lprect->right, lprect->bottom );
1492 if (lppop->nItems == 0)
1494 retvalue = GetSystemMetrics(SM_CYMENU);
1495 goto END;
1498 for (i = 0; i < lppop->nItems; i++)
1500 MENU_DrawMenuItem( hwnd, (HMENU)wndPtr->wIDmenu, hwnd,
1501 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
1503 retvalue = lppop->Height;
1505 END:
1506 if (hfontOld)
1507 SelectObject (hDC, hfontOld);
1509 WIN_ReleaseWndPtr(wndPtr);
1510 return retvalue;
1513 /***********************************************************************
1514 * MENU_PatchResidentPopup
1516 BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
1518 WND *pTPWnd = MENU_GetTopPopupWnd();
1520 if( pTPWnd )
1522 HTASK16 hTask = 0;
1524 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1525 checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTPWnd->hmemTaskQ,
1526 pTPWnd->owner ? pTPWnd->owner->hwndSelf : 0);
1528 switch( checkQueue )
1530 case 0: /* checkWnd is the new popup owner */
1531 if( checkWnd )
1533 pTPWnd->owner = checkWnd;
1534 if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
1535 hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
1537 break;
1539 case 0xFFFF: /* checkWnd is destroyed */
1540 if( pTPWnd->owner == checkWnd )
1541 pTPWnd->owner = NULL;
1542 MENU_ReleaseTopPopupWnd();
1543 return TRUE;
1545 default: /* checkQueue is exiting */
1546 if( pTPWnd->hmemTaskQ == checkQueue )
1548 hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
1549 hTask = TASK_GetNextTask( hTask );
1551 break;
1554 if( hTask )
1556 TDB* task = (TDB*)GlobalLock16( hTask );
1557 if( task )
1559 pTPWnd->hInstance = task->hInstance;
1560 pTPWnd->hmemTaskQ = task->hQueue;
1561 MENU_ReleaseTopPopupWnd();
1562 return TRUE;
1564 else WARN("failed to patch resident popup.\n");
1567 MENU_ReleaseTopPopupWnd();
1568 return FALSE;
1571 /***********************************************************************
1572 * MENU_ShowPopup
1574 * Display a popup menu.
1576 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1577 INT x, INT y, INT xanchor, INT yanchor )
1579 POPUPMENU *menu;
1580 WND *wndOwner = NULL;
1582 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1583 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1585 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1586 if (menu->FocusedItem != NO_SELECTED_ITEM)
1588 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1589 menu->FocusedItem = NO_SELECTED_ITEM;
1592 /* store the owner for DrawItem*/
1593 menu->hwndOwner = hwndOwner;
1595 if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
1597 UINT width, height;
1599 MENU_PopupMenuCalcSize( menu, hwndOwner );
1601 /* adjust popup menu pos so that it fits within the desktop */
1603 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1604 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1606 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1608 if( xanchor )
1609 x -= width - xanchor;
1610 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1611 x = GetSystemMetrics(SM_CXSCREEN) - width;
1613 if( x < 0 ) x = 0;
1615 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1617 if( yanchor )
1618 y -= height + yanchor;
1619 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1620 y = GetSystemMetrics(SM_CYSCREEN) - height;
1622 if( y < 0 ) y = 0;
1624 if( TWEAK_WineLook == WIN31_LOOK )
1626 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1627 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1630 /* NOTE: In Windows, top menu popup is not owned. */
1631 if (!pTopPopupWnd) /* create top level popup menu window */
1633 assert( uSubPWndLevel == 0 );
1635 pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1636 WS_POPUP, x, y, width, height,
1637 hwndOwner, 0, wndOwner->hInstance,
1638 (LPVOID)hmenu ));
1639 if (!pTopPopupWnd)
1641 WIN_ReleaseWndPtr(wndOwner);
1642 return FALSE;
1644 menu->hWnd = pTopPopupWnd->hwndSelf;
1645 MENU_ReleaseTopPopupWnd();
1647 else
1648 if( uSubPWndLevel )
1650 /* create a new window for the submenu */
1652 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1653 WS_POPUP, x, y, width, height,
1654 hwndOwner, 0, wndOwner->hInstance,
1655 (LPVOID)hmenu );
1656 if( !menu->hWnd )
1658 WIN_ReleaseWndPtr(wndOwner);
1659 return FALSE;
1662 else /* top level popup menu window already exists */
1664 WND *pTPWnd = MENU_GetTopPopupWnd();
1665 menu->hWnd = pTPWnd->hwndSelf;
1667 MENU_PatchResidentPopup( 0, wndOwner );
1668 SendMessageA( pTPWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);
1670 /* adjust its size */
1672 SetWindowPos( menu->hWnd, 0, x, y, width, height,
1673 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
1674 MENU_ReleaseTopPopupWnd();
1677 uSubPWndLevel++; /* menu level counter */
1679 /* Display the window */
1681 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1682 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1683 UpdateWindow( menu->hWnd );
1684 WIN_ReleaseWndPtr(wndOwner);
1685 return TRUE;
1687 return FALSE;
1691 /***********************************************************************
1692 * MENU_SelectItem
1694 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1695 BOOL sendMenuSelect, HMENU topmenu )
1697 LPPOPUPMENU lppop;
1698 HDC hdc;
1700 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1702 lppop = MENU_GetMenu( hmenu );
1703 if ((!lppop) || (!lppop->nItems)) return;
1705 if (lppop->FocusedItem == wIndex) return;
1706 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1707 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1709 SelectObject( hdc, hMenuFont);
1711 /* Clear previous highlighted item */
1712 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1714 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1715 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1716 lppop->Height, !(lppop->wFlags & MF_POPUP),
1717 ODA_SELECT );
1720 /* Highlight new item (if any) */
1721 lppop->FocusedItem = wIndex;
1722 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1724 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1725 lppop->items[wIndex].fState |= MF_HILITE;
1726 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1727 &lppop->items[wIndex], lppop->Height,
1728 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1730 if (sendMenuSelect)
1732 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1733 SendMessageA( hwndOwner, WM_MENUSELECT,
1734 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1735 ip->fType | ip->fState | MF_MOUSESELECT |
1736 (lppop->wFlags & MF_SYSMENU)), hmenu);
1739 else if (sendMenuSelect) {
1740 if(topmenu){
1741 int pos;
1742 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1743 POPUPMENU *ptm = (POPUPMENU *) USER_HEAP_LIN_ADDR( topmenu );
1744 MENUITEM *ip = &ptm->items[pos];
1745 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1746 ip->fType | ip->fState | MF_MOUSESELECT |
1747 (ptm->wFlags & MF_SYSMENU)), topmenu);
1751 ReleaseDC( lppop->hWnd, hdc );
1755 /***********************************************************************
1756 * MENU_MoveSelection
1758 * Moves currently selected item according to the offset parameter.
1759 * If there is no selection then it should select the last item if
1760 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1762 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1764 INT i;
1765 POPUPMENU *menu;
1767 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1769 menu = MENU_GetMenu( hmenu );
1770 if ((!menu) || (!menu->items)) return;
1772 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1774 if( menu->nItems == 1 ) return; else
1775 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1776 ; i += offset)
1777 if (!(menu->items[i].fType & MF_SEPARATOR))
1779 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1780 return;
1784 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1785 i >= 0 && i < menu->nItems ; i += offset)
1786 if (!(menu->items[i].fType & MF_SEPARATOR))
1788 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1789 return;
1794 /**********************************************************************
1795 * MENU_SetItemData
1797 * Set an item flags, id and text ptr. Called by InsertMenu() and
1798 * ModifyMenu().
1800 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1801 LPCSTR str )
1803 LPSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1805 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1807 if (IS_STRING_ITEM(flags))
1809 if (!str || !*str)
1811 flags |= MF_SEPARATOR;
1812 item->text = NULL;
1814 else
1816 LPSTR text;
1817 /* Item beginning with a backspace is a help item */
1818 if (*str == '\b')
1820 flags |= MF_HELP;
1821 str++;
1823 if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1824 item->text = text;
1827 else if (IS_BITMAP_ITEM(flags))
1828 item->text = (LPSTR)(HBITMAP)LOWORD(str);
1829 else item->text = NULL;
1831 if (flags & MF_OWNERDRAW)
1832 item->dwItemData = (DWORD)str;
1833 else
1834 item->dwItemData = 0;
1836 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1837 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1839 if (flags & MF_POPUP)
1841 POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1842 if (menu) menu->wFlags |= MF_POPUP;
1843 else
1845 item->wID = 0;
1846 item->hSubMenu = 0;
1847 item->fType = 0;
1848 item->fState = 0;
1849 return FALSE;
1853 item->wID = id;
1854 if (flags & MF_POPUP)
1855 item->hSubMenu = id;
1857 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1858 flags |= MF_POPUP; /* keep popup */
1860 item->fType = flags & TYPE_MASK;
1861 item->fState = (flags & STATE_MASK) &
1862 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1865 /* Don't call SetRectEmpty here! */
1868 if (prevText) HeapFree( SystemHeap, 0, prevText );
1870 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1871 return TRUE;
1875 /**********************************************************************
1876 * MENU_InsertItem
1878 * Insert a new item into a menu.
1880 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1882 MENUITEM *newItems;
1883 POPUPMENU *menu;
1885 if (!(menu = MENU_GetMenu(hMenu)))
1886 return NULL;
1888 /* Find where to insert new item */
1890 if (flags & MF_BYPOSITION) {
1891 if (pos > menu->nItems)
1892 pos = menu->nItems;
1893 } else {
1894 if (!MENU_FindItem( &hMenu, &pos, flags ))
1895 pos = menu->nItems;
1896 else {
1897 if (!(menu = MENU_GetMenu( hMenu )))
1898 return NULL;
1902 /* Create new items array */
1904 newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1905 if (!newItems)
1907 WARN("allocation failed\n" );
1908 return NULL;
1910 if (menu->nItems > 0)
1912 /* Copy the old array into the new */
1913 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1914 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1915 (menu->nItems-pos)*sizeof(MENUITEM) );
1916 HeapFree( SystemHeap, 0, menu->items );
1918 menu->items = newItems;
1919 menu->nItems++;
1920 memset( &newItems[pos], 0, sizeof(*newItems) );
1921 menu->Height = 0; /* force size recalculate */
1922 return &newItems[pos];
1926 /**********************************************************************
1927 * MENU_ParseResource
1929 * Parse a standard menu resource and add items to the menu.
1930 * Return a pointer to the end of the resource.
1932 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1934 WORD flags, id = 0;
1935 LPCSTR str;
1939 flags = GET_WORD(res);
1940 res += sizeof(WORD);
1941 if (!(flags & MF_POPUP))
1943 id = GET_WORD(res);
1944 res += sizeof(WORD);
1946 if (!IS_STRING_ITEM(flags))
1947 ERR("not a string item %04x\n", flags );
1948 str = res;
1949 if (!unicode) res += strlen(str) + 1;
1950 else res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1951 if (flags & MF_POPUP)
1953 HMENU hSubMenu = CreatePopupMenu();
1954 if (!hSubMenu) return NULL;
1955 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1956 return NULL;
1957 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1958 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1960 else /* Not a popup */
1962 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1963 else AppendMenuW( hMenu, flags, id,
1964 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1966 } while (!(flags & MF_END));
1967 return res;
1971 /**********************************************************************
1972 * MENUEX_ParseResource
1974 * Parse an extended menu resource and add items to the menu.
1975 * Return a pointer to the end of the resource.
1977 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1979 WORD resinfo;
1980 do {
1981 MENUITEMINFOW mii;
1983 mii.cbSize = sizeof(mii);
1984 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1985 mii.fType = GET_DWORD(res);
1986 res += sizeof(DWORD);
1987 mii.fState = GET_DWORD(res);
1988 res += sizeof(DWORD);
1989 mii.wID = GET_DWORD(res);
1990 res += sizeof(DWORD);
1991 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1992 res += sizeof(WORD);
1993 /* Align the text on a word boundary. */
1994 res += (~((int)res - 1)) & 1;
1995 mii.dwTypeData = (LPWSTR) res;
1996 res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
1997 /* Align the following fields on a dword boundary. */
1998 res += (~((int)res - 1)) & 3;
2000 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2002 LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
2003 0, mii.dwTypeData);
2004 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2005 mii.fType, mii.fState, mii.wID, resinfo, newstr);
2006 HeapFree( GetProcessHeap(), 0, newstr );
2009 if (resinfo & 1) { /* Pop-up? */
2010 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2011 res += sizeof(DWORD);
2012 mii.hSubMenu = CreatePopupMenu();
2013 if (!mii.hSubMenu)
2014 return NULL;
2015 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2016 DestroyMenu(mii.hSubMenu);
2017 return NULL;
2019 mii.fMask |= MIIM_SUBMENU;
2020 mii.fType |= MF_POPUP;
2022 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2023 } while (!(resinfo & MF_END));
2024 return res;
2028 /***********************************************************************
2029 * MENU_GetSubPopup
2031 * Return the handle of the selected sub-popup menu (if any).
2033 static HMENU MENU_GetSubPopup( HMENU hmenu )
2035 POPUPMENU *menu;
2036 MENUITEM *item;
2038 menu = MENU_GetMenu( hmenu );
2040 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2042 item = &menu->items[menu->FocusedItem];
2043 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2044 return item->hSubMenu;
2045 return 0;
2049 /***********************************************************************
2050 * MENU_HideSubPopups
2052 * Hide the sub-popup menus of this menu.
2054 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2055 BOOL sendMenuSelect )
2057 POPUPMENU *menu = MENU_GetMenu( hmenu );
2059 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2061 if (menu && uSubPWndLevel)
2063 HMENU hsubmenu;
2064 POPUPMENU *submenu;
2065 MENUITEM *item;
2067 if (menu->FocusedItem != NO_SELECTED_ITEM)
2069 item = &menu->items[menu->FocusedItem];
2070 if (!(item->fType & MF_POPUP) ||
2071 !(item->fState & MF_MOUSESELECT)) return;
2072 item->fState &= ~MF_MOUSESELECT;
2073 hsubmenu = item->hSubMenu;
2074 } else return;
2076 submenu = MENU_GetMenu( hsubmenu );
2077 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2078 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2080 if (submenu->hWnd == MENU_GetTopPopupWnd()->hwndSelf )
2082 ShowWindow( submenu->hWnd, SW_HIDE );
2083 uSubPWndLevel = 0;
2085 else
2087 DestroyWindow( submenu->hWnd );
2088 submenu->hWnd = 0;
2090 MENU_ReleaseTopPopupWnd();
2095 /***********************************************************************
2096 * MENU_ShowSubPopup
2098 * Display the sub-menu of the selected item of this menu.
2099 * Return the handle of the submenu, or hmenu if no submenu to display.
2101 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2102 BOOL selectFirst, UINT wFlags )
2104 RECT rect;
2105 POPUPMENU *menu;
2106 MENUITEM *item;
2107 WND *wndPtr;
2108 HDC hdc;
2110 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2112 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2114 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
2115 (menu->FocusedItem == NO_SELECTED_ITEM))
2117 WIN_ReleaseWndPtr(wndPtr);
2118 return hmenu;
2121 item = &menu->items[menu->FocusedItem];
2122 if (!(item->fType & MF_POPUP) ||
2123 (item->fState & (MF_GRAYED | MF_DISABLED)))
2125 WIN_ReleaseWndPtr(wndPtr);
2126 return hmenu;
2129 /* message must be send before using item,
2130 because nearly everything may by changed by the application ! */
2132 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2133 if (!(wFlags & TPM_NONOTIFY))
2134 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2135 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2137 item = &menu->items[menu->FocusedItem];
2138 rect = item->rect;
2140 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2141 if (!(item->fState & MF_HILITE))
2143 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2144 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2146 SelectObject( hdc, hMenuFont);
2148 item->fState |= MF_HILITE;
2149 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2150 ReleaseDC( menu->hWnd, hdc );
2152 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2153 item->rect = rect;
2155 item->fState |= MF_MOUSESELECT;
2157 if (IS_SYSTEM_MENU(menu))
2159 MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, GetClassLongA(wndPtr->hwndSelf, GCL_STYLE));
2161 NC_GetSysPopupPos( wndPtr, &rect );
2162 rect.top = rect.bottom;
2163 rect.right = GetSystemMetrics(SM_CXSIZE);
2164 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2166 else
2168 if (menu->wFlags & MF_POPUP)
2170 rect.left = wndPtr->rectWindow.left + item->rect.right - GetSystemMetrics(SM_CXBORDER);
2171 rect.top = wndPtr->rectWindow.top + item->rect.top;
2172 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2173 rect.bottom = item->rect.top - item->rect.bottom;
2175 else
2177 rect.left = wndPtr->rectWindow.left + item->rect.left;
2178 rect.top = wndPtr->rectWindow.top + item->rect.bottom;
2179 rect.right = item->rect.right - item->rect.left;
2180 rect.bottom = item->rect.bottom - item->rect.top;
2184 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2185 rect.left, rect.top, rect.right, rect.bottom );
2186 if (selectFirst)
2187 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2188 WIN_ReleaseWndPtr(wndPtr);
2189 return item->hSubMenu;
2194 /**********************************************************************
2195 * MENU_IsMenuActive
2197 BOOL MENU_IsMenuActive(void)
2199 return pTopPopupWnd && (pTopPopupWnd->dwStyle & WS_VISIBLE);
2202 /***********************************************************************
2203 * MENU_PtMenu
2205 * Walks menu chain trying to find a menu pt maps to.
2207 static HMENU MENU_PtMenu( HMENU hMenu, POINT16 pt )
2209 POPUPMENU *menu = MENU_GetMenu( hMenu );
2210 register UINT ht = menu->FocusedItem;
2212 /* try subpopup first (if any) */
2213 ht = (ht != NO_SELECTED_ITEM &&
2214 (menu->items[ht].fType & MF_POPUP) &&
2215 (menu->items[ht].fState & MF_MOUSESELECT))
2216 ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
2218 if( !ht ) /* check the current window (avoiding WM_HITTEST) */
2220 ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt );
2221 if( menu->wFlags & MF_POPUP )
2222 ht = (ht != (UINT)HTNOWHERE &&
2223 ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
2224 else
2226 WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
2228 ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu)
2229 : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0;
2230 WIN_ReleaseWndPtr(wndPtr);
2233 return (HMENU)ht;
2236 /***********************************************************************
2237 * MENU_ExecFocusedItem
2239 * Execute a menu item (for instance when user pressed Enter).
2240 * Return the wID of the executed item. Otherwise, -1 indicating
2241 * that no menu item wase executed;
2242 * Have to receive the flags for the TrackPopupMenu options to avoid
2243 * sending unwanted message.
2246 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2248 MENUITEM *item;
2249 POPUPMENU *menu = MENU_GetMenu( hMenu );
2251 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2253 if (!menu || !menu->nItems ||
2254 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2256 item = &menu->items[menu->FocusedItem];
2258 TRACE("%08x %08x %08x\n",
2259 hMenu, item->wID, item->hSubMenu);
2261 if (!(item->fType & MF_POPUP))
2263 if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
2265 /* If TPM_RETURNCMD is set you return the id, but
2266 do not send a message to the owner */
2267 if(!(wFlags & TPM_RETURNCMD))
2269 if( menu->wFlags & MF_SYSMENU )
2270 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2271 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2272 else
2273 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2275 return item->wID;
2278 else
2279 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2281 return -1;
2284 /***********************************************************************
2285 * MENU_SwitchTracking
2287 * Helper function for menu navigation routines.
2289 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2291 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2292 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2294 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2296 if( pmt->hTopMenu != hPtMenu &&
2297 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2299 /* both are top level menus (system and menu-bar) */
2300 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2301 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2302 pmt->hTopMenu = hPtMenu;
2304 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2305 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2309 /***********************************************************************
2310 * MENU_ButtonDown
2312 * Return TRUE if we can go on with menu tracking.
2314 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2316 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2318 if (hPtMenu)
2320 UINT id = 0;
2321 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2322 MENUITEM *item;
2324 if( IS_SYSTEM_MENU(ptmenu) )
2325 item = ptmenu->items;
2326 else
2327 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2329 if( item )
2331 if( ptmenu->FocusedItem != id )
2332 MENU_SwitchTracking( pmt, hPtMenu, id );
2334 /* If the popup menu is not already "popped" */
2335 if(!(item->fState & MF_MOUSESELECT ))
2337 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2339 /* In win31, a newly popped menu always remain opened for the next buttonup */
2340 if(TWEAK_WineLook == WIN31_LOOK)
2341 ptmenu->bTimeToHide = FALSE;
2344 return TRUE;
2346 /* Else the click was on the menu bar, finish the tracking */
2348 return FALSE;
2351 /***********************************************************************
2352 * MENU_ButtonUp
2354 * Return the value of MENU_ExecFocusedItem if
2355 * the selected item was not a popup. Else open the popup.
2356 * A -1 return value indicates that we go on with menu tracking.
2359 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2361 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2363 if (hPtMenu)
2365 UINT id = 0;
2366 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2367 MENUITEM *item;
2369 if( IS_SYSTEM_MENU(ptmenu) )
2370 item = ptmenu->items;
2371 else
2372 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2374 if( item && (ptmenu->FocusedItem == id ))
2376 if( !(item->fType & MF_POPUP) )
2377 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2379 /* If we are dealing with the top-level menu and that this */
2380 /* is a click on an already "poppped" item */
2381 /* Stop the menu tracking and close the opened submenus */
2382 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2383 return 0;
2385 ptmenu->bTimeToHide = TRUE;
2387 return -1;
2391 /***********************************************************************
2392 * MENU_MouseMove
2394 * Return TRUE if we can go on with menu tracking.
2396 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2398 UINT id = NO_SELECTED_ITEM;
2399 POPUPMENU *ptmenu = NULL;
2401 if( hPtMenu )
2403 ptmenu = MENU_GetMenu( hPtMenu );
2404 if( IS_SYSTEM_MENU(ptmenu) )
2405 id = 0;
2406 else
2407 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2410 if( id == NO_SELECTED_ITEM )
2412 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2413 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2416 else if( ptmenu->FocusedItem != id )
2418 MENU_SwitchTracking( pmt, hPtMenu, id );
2419 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2421 return TRUE;
2425 /***********************************************************************
2426 * MENU_DoNextMenu
2428 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2430 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2432 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2434 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2435 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2437 WND* wndPtr;
2438 HMENU hNewMenu;
2439 HWND hNewWnd;
2440 UINT id = 0;
2441 LRESULT l = SendMessageA( pmt->hOwnerWnd, WM_NEXTMENU, vk,
2442 (IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
2444 TRACE("%04x [%04x] -> %04x [%04x]\n",
2445 (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
2447 if( l == 0 )
2449 wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
2451 hNewWnd = pmt->hOwnerWnd;
2452 if( IS_SYSTEM_MENU(menu) )
2454 /* switch to the menu bar */
2456 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
2458 WIN_ReleaseWndPtr(wndPtr);
2459 return FALSE;
2462 hNewMenu = wndPtr->wIDmenu;
2463 if( vk == VK_LEFT )
2465 menu = MENU_GetMenu( hNewMenu );
2466 id = menu->nItems - 1;
2469 else if( wndPtr->dwStyle & WS_SYSMENU )
2471 /* switch to the system menu */
2472 hNewMenu = wndPtr->hSysMenu;
2474 else
2476 WIN_ReleaseWndPtr(wndPtr);
2477 return FALSE;
2479 WIN_ReleaseWndPtr(wndPtr);
2481 else /* application returned a new menu to switch to */
2483 hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
2485 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2487 wndPtr = WIN_FindWndPtr(hNewWnd);
2489 if( wndPtr->dwStyle & WS_SYSMENU &&
2490 GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
2492 /* get the real system menu */
2493 hNewMenu = wndPtr->hSysMenu;
2495 else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
2497 /* FIXME: Not sure what to do here, perhaps,
2498 * try to track hNewMenu as a popup? */
2500 TRACE(" -- got confused.\n");
2501 WIN_ReleaseWndPtr(wndPtr);
2502 return FALSE;
2504 WIN_ReleaseWndPtr(wndPtr);
2506 else return FALSE;
2509 if( hNewMenu != pmt->hTopMenu )
2511 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2512 FALSE, 0 );
2513 if( pmt->hCurrentMenu != pmt->hTopMenu )
2514 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2517 if( hNewWnd != pmt->hOwnerWnd )
2519 ReleaseCapture();
2520 pmt->hOwnerWnd = hNewWnd;
2521 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2524 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2525 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2527 return TRUE;
2529 return FALSE;
2532 /***********************************************************************
2533 * MENU_SuspendPopup
2535 * The idea is not to show the popup if the next input message is
2536 * going to hide it anyway.
2538 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2540 MSG msg;
2542 msg.hwnd = pmt->hOwnerWnd;
2544 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2545 pmt->trackFlags |= TF_SKIPREMOVE;
2547 switch( uMsg )
2549 case WM_KEYDOWN:
2550 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2551 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2553 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2554 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2555 if( msg.message == WM_KEYDOWN &&
2556 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2558 pmt->trackFlags |= TF_SUSPENDPOPUP;
2559 return TRUE;
2562 break;
2565 /* failures go through this */
2566 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2567 return FALSE;
2570 /***********************************************************************
2571 * MENU_KeyLeft
2573 * Handle a VK_LEFT key event in a menu.
2575 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2577 POPUPMENU *menu;
2578 HMENU hmenutmp, hmenuprev;
2579 UINT prevcol;
2581 hmenuprev = hmenutmp = pmt->hTopMenu;
2582 menu = MENU_GetMenu( hmenutmp );
2584 /* Try to move 1 column left (if possible) */
2585 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2586 NO_SELECTED_ITEM ) {
2588 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2589 prevcol, TRUE, 0 );
2590 return;
2593 /* close topmost popup */
2594 while (hmenutmp != pmt->hCurrentMenu)
2596 hmenuprev = hmenutmp;
2597 hmenutmp = MENU_GetSubPopup( hmenuprev );
2600 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2601 pmt->hCurrentMenu = hmenuprev;
2603 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2605 /* move menu bar selection if no more popups are left */
2607 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2608 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2610 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2612 /* A sublevel menu was displayed - display the next one
2613 * unless there is another displacement coming up */
2615 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2616 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2617 pmt->hTopMenu, TRUE, wFlags);
2623 /***********************************************************************
2624 * MENU_KeyRight
2626 * Handle a VK_RIGHT key event in a menu.
2628 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2630 HMENU hmenutmp;
2631 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2632 UINT nextcol;
2634 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2635 pmt->hCurrentMenu,
2636 (MENU_GetMenu(pmt->hCurrentMenu))->
2637 items[0].text,
2638 pmt->hTopMenu, menu->items[0].text );
2640 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2642 /* If already displaying a popup, try to display sub-popup */
2644 hmenutmp = pmt->hCurrentMenu;
2645 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2647 /* if subpopup was displayed then we are done */
2648 if (hmenutmp != pmt->hCurrentMenu) return;
2651 /* Check to see if there's another column */
2652 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2653 NO_SELECTED_ITEM ) {
2654 TRACE("Going to %d.\n", nextcol );
2655 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2656 nextcol, TRUE, 0 );
2657 return;
2660 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2662 if( pmt->hCurrentMenu != pmt->hTopMenu )
2664 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2665 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2666 } else hmenutmp = 0;
2668 /* try to move to the next item */
2669 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2670 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2672 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2673 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2674 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2675 pmt->hTopMenu, TRUE, wFlags);
2679 /***********************************************************************
2680 * MENU_TrackMenu
2682 * Menu tracking code.
2684 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2685 HWND hwnd, const RECT *lprect )
2687 MSG msg;
2688 POPUPMENU *menu;
2689 BOOL fRemove;
2690 INT executedMenuId = -1;
2691 MTRACKER mt;
2692 BOOL enterIdleSent = FALSE;
2694 mt.trackFlags = 0;
2695 mt.hCurrentMenu = hmenu;
2696 mt.hTopMenu = hmenu;
2697 mt.hOwnerWnd = hwnd;
2698 mt.pt.x = x;
2699 mt.pt.y = y;
2701 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2702 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2703 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2705 fEndMenu = FALSE;
2706 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2708 if (wFlags & TPM_BUTTONDOWN)
2710 /* Get the result in order to start the tracking or not */
2711 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2712 fEndMenu = !fRemove;
2715 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2717 while (!fEndMenu)
2719 menu = MENU_GetMenu( mt.hCurrentMenu );
2720 msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2722 /* we have to keep the message in the queue until it's
2723 * clear that menu loop is not over yet. */
2725 if (!MSG_InternalGetMessage( QMSG_WIN32A, &msg, msg.hwnd, mt.hOwnerWnd,
2726 MSGF_MENU, PM_NOREMOVE, !enterIdleSent, &enterIdleSent )) break;
2728 TranslateMessage( &msg );
2729 mt.pt = msg.pt;
2731 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2732 enterIdleSent=FALSE;
2734 fRemove = FALSE;
2735 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2737 /* Find a menu for this mouse event */
2738 POINT16 pt16;
2739 CONV_POINT32TO16( &msg.pt, &pt16 );
2740 hmenu = MENU_PtMenu( mt.hTopMenu, pt16 );
2742 switch(msg.message)
2744 /* no WM_NC... messages in captured state */
2746 case WM_RBUTTONDBLCLK:
2747 case WM_RBUTTONDOWN:
2748 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2749 /* fall through */
2750 case WM_LBUTTONDBLCLK:
2751 case WM_LBUTTONDOWN:
2752 /* If the message belongs to the menu, removes it from the queue */
2753 /* Else, end menu tracking */
2754 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2755 fEndMenu = !fRemove;
2756 break;
2758 case WM_RBUTTONUP:
2759 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2760 /* fall through */
2761 case WM_LBUTTONUP:
2762 /* Check if a menu was selected by the mouse */
2763 if (hmenu)
2765 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2767 /* End the loop if executedMenuId is an item ID */
2768 /* or if the job was done (executedMenuId = 0). */
2769 fEndMenu = fRemove = (executedMenuId != -1);
2771 /* No menu was selected by the mouse */
2772 /* if the function was called by TrackPopupMenu, continue
2773 with the menu tracking. If not, stop it */
2774 else
2775 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2777 break;
2779 case WM_MOUSEMOVE:
2780 /* In win95 winelook, the selected menu item must be changed every time the
2781 mouse moves. In Win31 winelook, the mouse button has to be held down */
2783 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2784 ( (msg.wParam & MK_LBUTTON) ||
2785 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2787 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2789 } /* switch(msg.message) - mouse */
2791 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2793 fRemove = TRUE; /* Keyboard messages are always removed */
2794 switch(msg.message)
2796 case WM_KEYDOWN:
2797 switch(msg.wParam)
2799 case VK_HOME:
2800 case VK_END:
2801 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2802 NO_SELECTED_ITEM, FALSE, 0 );
2803 /* fall through */
2804 case VK_UP:
2805 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2806 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2807 break;
2809 case VK_DOWN: /* If on menu bar, pull-down the menu */
2811 menu = MENU_GetMenu( mt.hCurrentMenu );
2812 if (!(menu->wFlags & MF_POPUP))
2813 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2814 else /* otherwise try to move selection */
2815 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2816 break;
2818 case VK_LEFT:
2819 MENU_KeyLeft( &mt, wFlags );
2820 break;
2822 case VK_RIGHT:
2823 MENU_KeyRight( &mt, wFlags );
2824 break;
2826 case VK_ESCAPE:
2827 fEndMenu = TRUE;
2828 break;
2830 case VK_F1:
2832 HELPINFO hi;
2833 hi.cbSize = sizeof(HELPINFO);
2834 hi.iContextType = HELPINFO_MENUITEM;
2835 if (menu->FocusedItem == NO_SELECTED_ITEM)
2836 hi.iCtrlId = 0;
2837 else
2838 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2839 hi.hItemHandle = hmenu;
2840 hi.dwContextId = menu->dwContextHelpID;
2841 hi.MousePos = msg.pt;
2842 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2843 break;
2846 default:
2847 break;
2849 break; /* WM_KEYDOWN */
2851 case WM_SYSKEYDOWN:
2852 switch(msg.wParam)
2854 case VK_MENU:
2855 fEndMenu = TRUE;
2856 break;
2859 break; /* WM_SYSKEYDOWN */
2861 case WM_CHAR:
2863 UINT pos;
2865 if (msg.wParam == '\r' || msg.wParam == ' ')
2867 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2868 fEndMenu = (executedMenuId != -1);
2870 break;
2873 /* Hack to avoid control chars. */
2874 /* We will find a better way real soon... */
2875 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2877 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
2878 LOWORD(msg.wParam), FALSE );
2879 if (pos == (UINT)-2) fEndMenu = TRUE;
2880 else if (pos == (UINT)-1) MessageBeep(0);
2881 else
2883 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2884 TRUE, 0 );
2885 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2886 fEndMenu = (executedMenuId != -1);
2889 break;
2890 } /* switch(msg.message) - kbd */
2892 else
2894 DispatchMessageA( &msg );
2897 if (!fEndMenu) fRemove = TRUE;
2899 /* finally remove message from the queue */
2901 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2902 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2903 else mt.trackFlags &= ~TF_SKIPREMOVE;
2906 ReleaseCapture();
2908 /* If dropdown is still painted and the close box is clicked on
2909 then the menu will be destroyed as part of the DispatchMessage above.
2910 This will then invalidate the menu handle in mt.hTopMenu. We should
2911 check for this first. */
2912 if( IsMenu( mt.hTopMenu ) )
2914 menu = MENU_GetMenu( mt.hTopMenu );
2916 if( IsWindow( mt.hOwnerWnd ) )
2918 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2920 if (menu && menu->wFlags & MF_POPUP)
2922 ShowWindow( menu->hWnd, SW_HIDE );
2923 uSubPWndLevel = 0;
2925 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2926 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2929 /* Reset the variable for hiding menu */
2930 if( menu ) menu->bTimeToHide = FALSE;
2933 /* The return value is only used by TrackPopupMenu */
2934 return ((executedMenuId != -1) ? executedMenuId : 0);
2937 /***********************************************************************
2938 * MENU_InitTracking
2940 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
2942 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
2944 HideCaret(0);
2946 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2947 if (!(wFlags & TPM_NONOTIFY))
2948 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2950 SendMessageA( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
2952 if (!(wFlags & TPM_NONOTIFY))
2953 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
2955 return TRUE;
2957 /***********************************************************************
2958 * MENU_ExitTracking
2960 static BOOL MENU_ExitTracking(HWND hWnd)
2962 TRACE("hwnd=0x%04x\n", hWnd);
2964 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2965 ShowCaret(0);
2966 return TRUE;
2969 /***********************************************************************
2970 * MENU_TrackMouseMenuBar
2972 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2974 void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt )
2976 HWND hWnd = wndPtr->hwndSelf;
2977 HMENU hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
2978 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2980 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr, ht, pt.x, pt.y);
2982 if (IsMenu(hMenu))
2984 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2985 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
2986 MENU_ExitTracking(hWnd);
2991 /***********************************************************************
2992 * MENU_TrackKbdMenuBar
2994 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2996 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
2998 UINT uItem = NO_SELECTED_ITEM;
2999 HMENU hTrackMenu;
3000 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3002 /* find window that has a menu */
3004 while( wndPtr->dwStyle & WS_CHILD)
3005 if( !(wndPtr = wndPtr->parent) ) return;
3007 /* check if we have to track a system menu */
3009 if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) ||
3010 !wndPtr->wIDmenu || vkey == VK_SPACE )
3012 if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
3013 hTrackMenu = wndPtr->hSysMenu;
3014 uItem = 0;
3015 wParam |= HTSYSMENU; /* prevent item lookup */
3017 else
3018 hTrackMenu = wndPtr->wIDmenu;
3020 if (IsMenu( hTrackMenu ))
3022 MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu, FALSE, wFlags );
3024 if( vkey && vkey != VK_SPACE )
3026 uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu,
3027 vkey, (wParam & HTSYSMENU) );
3028 if( uItem >= (UINT)(-2) )
3030 if( uItem == (UINT)(-1) ) MessageBeep(0);
3031 hTrackMenu = 0;
3035 if( hTrackMenu )
3037 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE, 0 );
3039 if( uItem == NO_SELECTED_ITEM )
3040 MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
3041 else if( vkey )
3042 PostMessageA( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
3044 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, wndPtr->hwndSelf, NULL );
3047 MENU_ExitTracking (wndPtr->hwndSelf);
3052 /**********************************************************************
3053 * TrackPopupMenu16 (USER.416)
3055 BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
3056 INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
3058 RECT r;
3059 if (lpRect)
3060 CONV_RECT16TO32( lpRect, &r );
3061 return TrackPopupMenu( hMenu, wFlags, x, y, nReserved, hWnd,
3062 lpRect ? &r : NULL );
3066 /**********************************************************************
3067 * TrackPopupMenu (USER32.549)
3069 * Like the win32 API, the function return the command ID only if the
3070 * flag TPM_RETURNCMD is on.
3073 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3074 INT nReserved, HWND hWnd, const RECT *lpRect )
3076 BOOL ret = FALSE;
3078 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3080 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3081 if (!(wFlags & TPM_NONOTIFY))
3082 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3084 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3085 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3086 MENU_ExitTracking(hWnd);
3088 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3089 ret = 1;
3091 return ret;
3094 /**********************************************************************
3095 * TrackPopupMenuEx (USER32.550)
3097 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3098 HWND hWnd, LPTPMPARAMS lpTpm )
3100 FIXME("not fully implemented\n" );
3101 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3102 lpTpm ? &lpTpm->rcExclude : NULL );
3105 /***********************************************************************
3106 * PopupMenuWndProc
3108 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3110 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
3111 LPARAM lParam )
3113 WND* wndPtr = WIN_FindWndPtr(hwnd);
3114 LRESULT retvalue;
3116 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3117 hwnd, message, wParam, lParam);
3119 switch(message)
3121 case WM_CREATE:
3123 CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
3124 SetWindowLongA( hwnd, 0, (LONG)cs->lpCreateParams );
3125 retvalue = 0;
3126 goto END;
3129 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3130 retvalue = MA_NOACTIVATE;
3131 goto END;
3133 case WM_PAINT:
3135 PAINTSTRUCT ps;
3136 BeginPaint( hwnd, &ps );
3137 MENU_DrawPopupMenu( hwnd, ps.hdc,
3138 (HMENU)GetWindowLongA( hwnd, 0 ) );
3139 EndPaint( hwnd, &ps );
3140 retvalue = 0;
3141 goto END;
3143 case WM_ERASEBKGND:
3144 retvalue = 1;
3145 goto END;
3147 case WM_DESTROY:
3149 /* zero out global pointer in case resident popup window
3150 * was somehow destroyed. */
3152 if(MENU_GetTopPopupWnd() )
3154 if( hwnd == pTopPopupWnd->hwndSelf )
3156 ERR("resident popup destroyed!\n");
3158 MENU_DestroyTopPopupWnd();
3159 uSubPWndLevel = 0;
3161 else
3162 uSubPWndLevel--;
3163 MENU_ReleaseTopPopupWnd();
3165 break;
3167 case WM_SHOWWINDOW:
3169 if( wParam )
3171 if( !(*(HMENU*)wndPtr->wExtra) )
3172 ERR("no menu to display\n");
3174 else
3175 *(HMENU*)wndPtr->wExtra = 0;
3176 break;
3178 case MM_SETMENUHANDLE:
3180 *(HMENU*)wndPtr->wExtra = (HMENU)wParam;
3181 break;
3183 case MM_GETMENUHANDLE:
3185 retvalue = *(HMENU*)wndPtr->wExtra;
3186 goto END;
3188 default:
3189 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
3190 goto END;
3192 retvalue = 0;
3193 END:
3194 WIN_ReleaseWndPtr(wndPtr);
3195 return retvalue;
3199 /***********************************************************************
3200 * MENU_GetMenuBarHeight
3202 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3204 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3205 INT orgX, INT orgY )
3207 HDC hdc;
3208 RECT rectBar;
3209 WND *wndPtr;
3210 LPPOPUPMENU lppop;
3211 UINT retvalue;
3213 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3214 hwnd, menubarWidth, orgX, orgY );
3216 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
3217 return 0;
3219 if (!(lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu)))
3221 WIN_ReleaseWndPtr(wndPtr);
3222 return 0;
3225 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3226 SelectObject( hdc, hMenuFont);
3227 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3228 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3229 ReleaseDC( hwnd, hdc );
3230 retvalue = lppop->Height;
3231 WIN_ReleaseWndPtr(wndPtr);
3232 return retvalue;
3236 /*******************************************************************
3237 * ChangeMenu16 (USER.153)
3239 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3240 UINT16 id, UINT16 flags )
3242 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3243 hMenu, pos, (DWORD)data, id, flags );
3244 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3245 id, data );
3247 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3248 /* for MF_DELETE. We should check the parameters for all others */
3249 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3251 if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3252 if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3253 id, data );
3254 if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
3255 flags & MF_BYPOSITION ? pos : id,
3256 flags & ~MF_REMOVE );
3257 /* Default: MF_INSERT */
3258 return InsertMenu16( hMenu, pos, flags, id, data );
3262 /*******************************************************************
3263 * ChangeMenuA (USER32.23)
3265 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3266 UINT id, UINT flags )
3268 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3269 hMenu, pos, (DWORD)data, id, flags );
3270 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3271 id, data );
3272 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3273 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3274 id, data );
3275 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3276 flags & MF_BYPOSITION ? pos : id,
3277 flags & ~MF_REMOVE );
3278 /* Default: MF_INSERT */
3279 return InsertMenuA( hMenu, pos, flags, id, data );
3283 /*******************************************************************
3284 * ChangeMenuW (USER32.24)
3286 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3287 UINT id, UINT flags )
3289 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3290 hMenu, pos, (DWORD)data, id, flags );
3291 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3292 id, data );
3293 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3294 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3295 id, data );
3296 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3297 flags & MF_BYPOSITION ? pos : id,
3298 flags & ~MF_REMOVE );
3299 /* Default: MF_INSERT */
3300 return InsertMenuW( hMenu, pos, flags, id, data );
3304 /*******************************************************************
3305 * CheckMenuItem16 (USER.154)
3307 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
3309 return (BOOL16)CheckMenuItem( hMenu, id, flags );
3313 /*******************************************************************
3314 * CheckMenuItem (USER32.46)
3316 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3318 MENUITEM *item;
3319 DWORD ret;
3321 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3322 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3323 ret = item->fState & MF_CHECKED;
3324 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3325 else item->fState &= ~MF_CHECKED;
3326 return ret;
3330 /**********************************************************************
3331 * EnableMenuItem16 (USER.155)
3333 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3335 return EnableMenuItem( hMenu, wItemID, wFlags );
3339 /**********************************************************************
3340 * EnableMenuItem (USER32.170)
3342 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3344 UINT oldflags;
3345 MENUITEM *item;
3346 POPUPMENU *menu;
3348 TRACE("(%04x, %04X, %04X) !\n",
3349 hMenu, wItemID, wFlags);
3351 /* Get the Popupmenu to access the owner menu */
3352 if (!(menu = MENU_GetMenu(hMenu)))
3353 return (UINT)-1;
3355 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3356 return (UINT)-1;
3358 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3359 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3361 /* In win95 if the close item in the system menu change update the close button */
3362 if (TWEAK_WineLook == WIN95_LOOK)
3363 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3365 if (menu->hSysMenuOwner != 0)
3367 POPUPMENU* parentMenu;
3369 /* Get the parent menu to access*/
3370 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3371 return (UINT)-1;
3373 /* Refresh the frame to reflect the change*/
3374 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3375 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3379 return oldflags;
3383 /*******************************************************************
3384 * GetMenuString16 (USER.161)
3386 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3387 LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
3389 return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
3393 /*******************************************************************
3394 * GetMenuStringA (USER32.268)
3396 INT WINAPI GetMenuStringA(
3397 HMENU hMenu, /* [in] menuhandle */
3398 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3399 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3400 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3401 UINT wFlags /* [in] MF_ flags */
3403 MENUITEM *item;
3405 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3406 hMenu, wItemID, str, nMaxSiz, wFlags );
3407 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3408 if (!IS_STRING_ITEM(item->fType)) return 0;
3409 if (!str || !nMaxSiz) return strlen(item->text);
3410 str[0] = '\0';
3411 lstrcpynA( str, item->text, nMaxSiz );
3412 TRACE("returning '%s'\n", str );
3413 return strlen(str);
3417 /*******************************************************************
3418 * GetMenuStringW (USER32.269)
3420 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3421 LPWSTR str, INT nMaxSiz, UINT wFlags )
3423 MENUITEM *item;
3425 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3426 hMenu, wItemID, str, nMaxSiz, wFlags );
3427 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3428 if (!IS_STRING_ITEM(item->fType)) return 0;
3429 if (!str || !nMaxSiz) return strlen(item->text);
3430 str[0] = '\0';
3431 lstrcpynAtoW( str, item->text, nMaxSiz );
3432 return lstrlenW(str);
3436 /**********************************************************************
3437 * HiliteMenuItem16 (USER.162)
3439 BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
3440 UINT16 wHilite )
3442 return HiliteMenuItem( hWnd, hMenu, wItemID, wHilite );
3446 /**********************************************************************
3447 * HiliteMenuItem (USER32.318)
3449 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3450 UINT wHilite )
3452 LPPOPUPMENU menu;
3453 TRACE("(%04x, %04x, %04x, %04x);\n",
3454 hWnd, hMenu, wItemID, wHilite);
3455 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3456 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3457 if (menu->FocusedItem == wItemID) return TRUE;
3458 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3459 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3460 return TRUE;
3464 /**********************************************************************
3465 * GetMenuState16 (USER.250)
3467 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3469 return GetMenuState( hMenu, wItemID, wFlags );
3473 /**********************************************************************
3474 * GetMenuState (USER32.267)
3476 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3478 MENUITEM *item;
3479 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3480 hMenu, wItemID, wFlags);
3481 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3482 debug_print_menuitem (" item: ", item, "");
3483 if (item->fType & MF_POPUP)
3485 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3486 if (!menu) return -1;
3487 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3489 else
3491 /* We used to (from way back then) mask the result to 0xff. */
3492 /* I don't know why and it seems wrong as the documented */
3493 /* return flag MF_SEPARATOR is outside that mask. */
3494 return (item->fType | item->fState);
3499 /**********************************************************************
3500 * GetMenuItemCount16 (USER.263)
3502 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3504 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3505 if (!menu) return -1;
3506 TRACE("(%04x) returning %d\n",
3507 hMenu, menu->nItems );
3508 return menu->nItems;
3512 /**********************************************************************
3513 * GetMenuItemCount (USER32.262)
3515 INT WINAPI GetMenuItemCount( HMENU hMenu )
3517 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3518 if (!menu) return -1;
3519 TRACE("(%04x) returning %d\n",
3520 hMenu, menu->nItems );
3521 return menu->nItems;
3524 /**********************************************************************
3525 * GetMenuItemID16 (USER.264)
3527 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3529 return (UINT16) GetMenuItemID (hMenu, nPos);
3532 /**********************************************************************
3533 * GetMenuItemID (USER32.263)
3535 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3537 MENUITEM * lpmi;
3539 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3540 if (lpmi->fType & MF_POPUP) return -1;
3541 return lpmi->wID;
3545 /*******************************************************************
3546 * InsertMenu16 (USER.410)
3548 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3549 UINT16 id, SEGPTR data )
3551 UINT pos32 = (UINT)pos;
3552 if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3553 if (IS_STRING_ITEM(flags) && data)
3554 return InsertMenuA( hMenu, pos32, flags, id,
3555 (LPSTR)PTR_SEG_TO_LIN(data) );
3556 return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3560 /*******************************************************************
3561 * InsertMenuA (USER32.322)
3563 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3564 UINT id, LPCSTR str )
3566 MENUITEM *item;
3568 if (IS_STRING_ITEM(flags) && str)
3569 TRACE("hMenu %04x, pos %d, flags %08x, "
3570 "id %04x, str '%s'\n",
3571 hMenu, pos, flags, id, str );
3572 else TRACE("hMenu %04x, pos %d, flags %08x, "
3573 "id %04x, str %08lx (not a string)\n",
3574 hMenu, pos, flags, id, (DWORD)str );
3576 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3578 if (!(MENU_SetItemData( item, flags, id, str )))
3580 RemoveMenu( hMenu, pos, flags );
3581 return FALSE;
3584 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3585 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3587 item->hCheckBit = item->hUnCheckBit = 0;
3588 return TRUE;
3592 /*******************************************************************
3593 * InsertMenuW (USER32.325)
3595 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3596 UINT id, LPCWSTR str )
3598 BOOL ret;
3600 if (IS_STRING_ITEM(flags) && str)
3602 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3603 ret = InsertMenuA( hMenu, pos, flags, id, newstr );
3604 HeapFree( GetProcessHeap(), 0, newstr );
3605 return ret;
3607 else return InsertMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3611 /*******************************************************************
3612 * AppendMenu16 (USER.411)
3614 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3616 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3620 /*******************************************************************
3621 * AppendMenuA (USER32.5)
3623 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3624 UINT id, LPCSTR data )
3626 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3630 /*******************************************************************
3631 * AppendMenuW (USER32.6)
3633 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3634 UINT id, LPCWSTR data )
3636 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3640 /**********************************************************************
3641 * RemoveMenu16 (USER.412)
3643 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3645 return RemoveMenu( hMenu, nPos, wFlags );
3649 /**********************************************************************
3650 * RemoveMenu (USER32.441)
3652 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3654 LPPOPUPMENU menu;
3655 MENUITEM *item;
3657 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3658 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3659 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3661 /* Remove item */
3663 MENU_FreeItemData( item );
3665 if (--menu->nItems == 0)
3667 HeapFree( SystemHeap, 0, menu->items );
3668 menu->items = NULL;
3670 else
3672 while(nPos < menu->nItems)
3674 *item = *(item+1);
3675 item++;
3676 nPos++;
3678 menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
3679 menu->nItems * sizeof(MENUITEM) );
3681 return TRUE;
3685 /**********************************************************************
3686 * DeleteMenu16 (USER.413)
3688 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3690 return DeleteMenu( hMenu, nPos, wFlags );
3694 /**********************************************************************
3695 * DeleteMenu (USER32.129)
3697 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3699 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3700 if (!item) return FALSE;
3701 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3702 /* nPos is now the position of the item */
3703 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3704 return TRUE;
3708 /*******************************************************************
3709 * ModifyMenu16 (USER.414)
3711 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3712 UINT16 id, SEGPTR data )
3714 if (IS_STRING_ITEM(flags))
3715 return ModifyMenuA( hMenu, pos, flags, id,
3716 (LPSTR)PTR_SEG_TO_LIN(data) );
3717 return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3721 /*******************************************************************
3722 * ModifyMenuA (USER32.397)
3724 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3725 UINT id, LPCSTR str )
3727 MENUITEM *item;
3729 if (IS_STRING_ITEM(flags))
3731 TRACE("%04x %d %04x %04x '%s'\n",
3732 hMenu, pos, flags, id, str ? str : "#NULL#" );
3733 if (!str) return FALSE;
3735 else
3737 TRACE("%04x %d %04x %04x %08lx\n",
3738 hMenu, pos, flags, id, (DWORD)str );
3741 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3742 return MENU_SetItemData( item, flags, id, str );
3746 /*******************************************************************
3747 * ModifyMenuW (USER32.398)
3749 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3750 UINT id, LPCWSTR str )
3752 BOOL ret;
3754 if (IS_STRING_ITEM(flags) && str)
3756 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3757 ret = ModifyMenuA( hMenu, pos, flags, id, newstr );
3758 HeapFree( GetProcessHeap(), 0, newstr );
3759 return ret;
3761 else return ModifyMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3765 /**********************************************************************
3766 * CreatePopupMenu16 (USER.415)
3768 HMENU16 WINAPI CreatePopupMenu16(void)
3770 return CreatePopupMenu();
3774 /**********************************************************************
3775 * CreatePopupMenu (USER32.82)
3777 HMENU WINAPI CreatePopupMenu(void)
3779 HMENU hmenu;
3780 POPUPMENU *menu;
3782 if (!(hmenu = CreateMenu())) return 0;
3783 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
3784 menu->wFlags |= MF_POPUP;
3785 menu->bTimeToHide = FALSE;
3786 return hmenu;
3790 /**********************************************************************
3791 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3793 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3795 return MAKELONG( check_bitmap_width, check_bitmap_height );
3799 /**********************************************************************
3800 * SetMenuItemBitmaps16 (USER.418)
3802 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3803 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3805 return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3809 /**********************************************************************
3810 * SetMenuItemBitmaps (USER32.490)
3812 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3813 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3815 MENUITEM *item;
3816 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3817 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3818 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3820 if (!hNewCheck && !hNewUnCheck)
3822 item->fState &= ~MF_USECHECKBITMAPS;
3824 else /* Install new bitmaps */
3826 item->hCheckBit = hNewCheck;
3827 item->hUnCheckBit = hNewUnCheck;
3828 item->fState |= MF_USECHECKBITMAPS;
3830 return TRUE;
3834 /**********************************************************************
3835 * CreateMenu16 (USER.151)
3837 HMENU16 WINAPI CreateMenu16(void)
3839 return CreateMenu();
3843 /**********************************************************************
3844 * CreateMenu (USER32.81)
3846 HMENU WINAPI CreateMenu(void)
3848 HMENU hMenu;
3849 LPPOPUPMENU menu;
3850 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3851 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3853 ZeroMemory(menu, sizeof(POPUPMENU));
3854 menu->wMagic = MENU_MAGIC;
3855 menu->FocusedItem = NO_SELECTED_ITEM;
3856 menu->bTimeToHide = FALSE;
3858 TRACE("return %04x\n", hMenu );
3860 return hMenu;
3864 /**********************************************************************
3865 * DestroyMenu16 (USER.152)
3867 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3869 return DestroyMenu( hMenu );
3873 /**********************************************************************
3874 * DestroyMenu (USER32.134)
3876 BOOL WINAPI DestroyMenu( HMENU hMenu )
3878 TRACE("(%04x)\n", hMenu);
3880 /* Silently ignore attempts to destroy default system popup */
3882 if (hMenu && hMenu != MENU_DefSysPopup)
3884 LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3885 WND *pTPWnd = MENU_GetTopPopupWnd();
3887 if( pTPWnd && (hMenu == *(HMENU*)pTPWnd->wExtra) )
3888 *(UINT*)pTPWnd->wExtra = 0;
3890 if (!IS_A_MENU(lppop)) lppop = NULL;
3891 if ( lppop )
3893 lppop->wMagic = 0; /* Mark it as destroyed */
3895 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
3896 (!pTPWnd || (lppop->hWnd != pTPWnd->hwndSelf)))
3897 DestroyWindow( lppop->hWnd );
3899 if (lppop->items) /* recursively destroy submenus */
3901 int i;
3902 MENUITEM *item = lppop->items;
3903 for (i = lppop->nItems; i > 0; i--, item++)
3905 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3906 MENU_FreeItemData( item );
3908 HeapFree( SystemHeap, 0, lppop->items );
3910 USER_HEAP_FREE( hMenu );
3911 MENU_ReleaseTopPopupWnd();
3913 else
3915 MENU_ReleaseTopPopupWnd();
3916 return FALSE;
3919 return (hMenu != MENU_DefSysPopup);
3923 /**********************************************************************
3924 * GetSystemMenu16 (USER.156)
3926 HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
3928 return GetSystemMenu( hWnd, bRevert );
3932 /**********************************************************************
3933 * GetSystemMenu (USER32.291)
3935 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3937 WND *wndPtr = WIN_FindWndPtr( hWnd );
3938 HMENU retvalue = 0;
3940 if (wndPtr)
3942 if( wndPtr->hSysMenu )
3944 if( bRevert )
3946 DestroyMenu(wndPtr->hSysMenu);
3947 wndPtr->hSysMenu = 0;
3949 else
3951 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3952 if( menu )
3954 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3955 menu->items[0].hSubMenu = MENU_CopySysPopup();
3957 else
3959 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3960 wndPtr->hSysMenu, hWnd);
3961 wndPtr->hSysMenu = 0;
3966 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3967 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3969 if( wndPtr->hSysMenu )
3971 POPUPMENU *menu;
3972 retvalue = GetSubMenu16(wndPtr->hSysMenu, 0);
3974 /* Store the dummy sysmenu handle to facilitate the refresh */
3975 /* of the close button if the SC_CLOSE item change */
3976 menu = MENU_GetMenu(retvalue);
3977 if ( menu )
3978 menu->hSysMenuOwner = wndPtr->hSysMenu;
3980 WIN_ReleaseWndPtr(wndPtr);
3982 return retvalue;
3986 /*******************************************************************
3987 * SetSystemMenu16 (USER.280)
3989 BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
3991 return SetSystemMenu( hwnd, hMenu );
3995 /*******************************************************************
3996 * SetSystemMenu (USER32.508)
3998 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
4000 WND *wndPtr = WIN_FindWndPtr(hwnd);
4002 if (wndPtr)
4004 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
4005 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
4006 WIN_ReleaseWndPtr(wndPtr);
4007 return TRUE;
4009 return FALSE;
4013 /**********************************************************************
4014 * GetMenu16 (USER.157)
4016 HMENU16 WINAPI GetMenu16( HWND16 hWnd )
4018 return (HMENU16)GetMenu(hWnd);
4022 /**********************************************************************
4023 * GetMenu (USER32.257)
4025 HMENU WINAPI GetMenu( HWND hWnd )
4027 HMENU retvalue;
4028 WND * wndPtr = WIN_FindWndPtr(hWnd);
4029 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4031 retvalue = (HMENU)wndPtr->wIDmenu;
4032 goto END;
4034 retvalue = 0;
4035 END:
4036 WIN_ReleaseWndPtr(wndPtr);
4037 return retvalue;
4041 /**********************************************************************
4042 * SetMenu16 (USER.158)
4044 BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
4046 return SetMenu( hWnd, hMenu );
4050 /**********************************************************************
4051 * SetMenu (USER32.487)
4053 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4055 WND * wndPtr = WIN_FindWndPtr(hWnd);
4057 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4059 if (hMenu && !IsMenu(hMenu))
4061 WARN("hMenu is not a menu handle\n");
4062 return FALSE;
4066 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
4068 if (GetCapture() == hWnd) ReleaseCapture();
4070 wndPtr->wIDmenu = (UINT)hMenu;
4071 if (hMenu != 0)
4073 LPPOPUPMENU lpmenu;
4075 if (!(lpmenu = MENU_GetMenu(hMenu)))
4077 WIN_ReleaseWndPtr(wndPtr);
4078 return FALSE;
4080 lpmenu->hWnd = hWnd;
4081 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
4082 lpmenu->Height = 0; /* Make sure we recalculate the size */
4084 if (IsWindowVisible(hWnd))
4085 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4086 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4087 WIN_ReleaseWndPtr(wndPtr);
4088 return TRUE;
4090 WIN_ReleaseWndPtr(wndPtr);
4091 return FALSE;
4096 /**********************************************************************
4097 * GetSubMenu16 (USER.159)
4099 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
4101 return GetSubMenu( hMenu, nPos );
4105 /**********************************************************************
4106 * GetSubMenu (USER32.288)
4108 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4110 MENUITEM * lpmi;
4112 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4113 if (!(lpmi->fType & MF_POPUP)) return 0;
4114 return lpmi->hSubMenu;
4118 /**********************************************************************
4119 * DrawMenuBar16 (USER.160)
4121 void WINAPI DrawMenuBar16( HWND16 hWnd )
4123 DrawMenuBar( hWnd );
4127 /**********************************************************************
4128 * DrawMenuBar (USER32.161)
4130 BOOL WINAPI DrawMenuBar( HWND hWnd )
4132 LPPOPUPMENU lppop;
4133 WND *wndPtr = WIN_FindWndPtr(hWnd);
4134 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
4136 lppop = MENU_GetMenu((HMENU16)wndPtr->wIDmenu);
4137 if (lppop == NULL)
4139 WIN_ReleaseWndPtr(wndPtr);
4140 return FALSE;
4143 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4144 lppop->hwndOwner = hWnd;
4145 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4146 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4147 WIN_ReleaseWndPtr(wndPtr);
4148 return TRUE;
4150 WIN_ReleaseWndPtr(wndPtr);
4151 return FALSE;
4155 /***********************************************************************
4156 * EndMenu (USER.187) (USER32.175)
4158 void WINAPI EndMenu(void)
4161 * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
4164 fEndMenu = TRUE;
4168 /***********************************************************************
4169 * LookupMenuHandle (USER.217)
4171 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4173 HMENU hmenu32 = hmenu;
4174 UINT id32 = id;
4175 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4176 else return hmenu32;
4180 /**********************************************************************
4181 * LoadMenu16 (USER.150)
4183 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, SEGPTR name )
4185 HRSRC16 hRsrc;
4186 HGLOBAL16 handle;
4187 HMENU16 hMenu;
4189 if (HIWORD(name))
4191 char *str = (char *)PTR_SEG_TO_LIN( name );
4192 TRACE("(%04x,'%s')\n", instance, str );
4193 if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
4195 else
4196 TRACE("(%04x,%04x)\n",instance,LOWORD(name));
4198 if (!name) return 0;
4200 /* check for Win32 module */
4201 if (HIWORD(instance))
4202 return LoadMenuA(instance,PTR_SEG_TO_LIN(name));
4203 instance = GetExePtr( instance );
4205 if (!(hRsrc = FindResource16( instance, name, RT_MENU16 ))) return 0;
4206 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4207 hMenu = LoadMenuIndirect16(LockResource16(handle));
4208 FreeResource16( handle );
4209 return hMenu;
4213 /*****************************************************************
4214 * LoadMenuA (USER32.370)
4216 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4218 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4219 if (!hrsrc) return 0;
4220 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4224 /*****************************************************************
4225 * LoadMenuW (USER32.373)
4227 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4229 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4230 if (!hrsrc) return 0;
4231 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4235 /**********************************************************************
4236 * LoadMenuIndirect16 (USER.220)
4238 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4240 HMENU16 hMenu;
4241 WORD version, offset;
4242 LPCSTR p = (LPCSTR)template;
4244 TRACE("(%p)\n", template );
4245 version = GET_WORD(p);
4246 p += sizeof(WORD);
4247 if (version)
4249 WARN("version must be 0 for Win16\n" );
4250 return 0;
4252 offset = GET_WORD(p);
4253 p += sizeof(WORD) + offset;
4254 if (!(hMenu = CreateMenu())) return 0;
4255 if (!MENU_ParseResource( p, hMenu, FALSE ))
4257 DestroyMenu( hMenu );
4258 return 0;
4260 return hMenu;
4264 /**********************************************************************
4265 * LoadMenuIndirectA (USER32.371)
4267 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4269 HMENU16 hMenu;
4270 WORD version, offset;
4271 LPCSTR p = (LPCSTR)template;
4273 TRACE("%p\n", template );
4274 version = GET_WORD(p);
4275 p += sizeof(WORD);
4276 switch (version)
4278 case 0:
4279 offset = GET_WORD(p);
4280 p += sizeof(WORD) + offset;
4281 if (!(hMenu = CreateMenu())) return 0;
4282 if (!MENU_ParseResource( p, hMenu, TRUE ))
4284 DestroyMenu( hMenu );
4285 return 0;
4287 return hMenu;
4288 case 1:
4289 offset = GET_WORD(p);
4290 p += sizeof(WORD) + offset;
4291 if (!(hMenu = CreateMenu())) return 0;
4292 if (!MENUEX_ParseResource( p, hMenu))
4294 DestroyMenu( hMenu );
4295 return 0;
4297 return hMenu;
4298 default:
4299 ERR("version %d not supported.\n", version);
4300 return 0;
4305 /**********************************************************************
4306 * LoadMenuIndirectW (USER32.372)
4308 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4310 /* FIXME: is there anything different between A and W? */
4311 return LoadMenuIndirectA( template );
4315 /**********************************************************************
4316 * IsMenu16 (USER.358)
4318 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4320 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4321 return IS_A_MENU(menu);
4325 /**********************************************************************
4326 * IsMenu (USER32.346)
4328 BOOL WINAPI IsMenu(HMENU hmenu)
4330 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4331 return IS_A_MENU(menu);
4334 /**********************************************************************
4335 * GetMenuItemInfo_common
4338 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4339 LPMENUITEMINFOA lpmii, BOOL unicode)
4341 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4343 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4345 if (!menu)
4346 return FALSE;
4348 if (lpmii->fMask & MIIM_TYPE) {
4349 lpmii->fType = menu->fType;
4350 switch (MENU_ITEM_TYPE(menu->fType)) {
4351 case MF_STRING:
4352 if (menu->text) {
4353 int len = lstrlenA(menu->text);
4354 if(lpmii->dwTypeData && lpmii->cch) {
4355 if (unicode)
4356 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4357 lpmii->cch);
4358 else
4359 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4360 /* if we've copied a substring we return its length */
4361 if(lpmii->cch <= len)
4362 lpmii->cch--;
4363 } else /* return length of string */
4364 lpmii->cch = len;
4366 break;
4367 case MF_OWNERDRAW:
4368 case MF_BITMAP:
4369 lpmii->dwTypeData = menu->text;
4370 /* fall through */
4371 default:
4372 lpmii->cch = 0;
4376 if (lpmii->fMask & MIIM_STRING) {
4377 if(lpmii->dwTypeData && lpmii->cch) {
4378 if (unicode)
4379 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text,
4380 lpmii->cch);
4381 else
4382 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4384 lpmii->cch = lstrlenA(menu->text);
4387 if (lpmii->fMask & MIIM_FTYPE)
4388 lpmii->fType = menu->fType;
4390 if (lpmii->fMask & MIIM_BITMAP)
4391 lpmii->hbmpItem = menu->hbmpItem;
4393 if (lpmii->fMask & MIIM_STATE)
4394 lpmii->fState = menu->fState;
4396 if (lpmii->fMask & MIIM_ID)
4397 lpmii->wID = menu->wID;
4399 if (lpmii->fMask & MIIM_SUBMENU)
4400 lpmii->hSubMenu = menu->hSubMenu;
4402 if (lpmii->fMask & MIIM_CHECKMARKS) {
4403 lpmii->hbmpChecked = menu->hCheckBit;
4404 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4406 if (lpmii->fMask & MIIM_DATA)
4407 lpmii->dwItemData = menu->dwItemData;
4409 return TRUE;
4412 /**********************************************************************
4413 * GetMenuItemInfoA (USER32.264)
4415 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4416 LPMENUITEMINFOA lpmii)
4418 return GetMenuItemInfo_common (hmenu, item, bypos, lpmii, FALSE);
4421 /**********************************************************************
4422 * GetMenuItemInfoW (USER32.265)
4424 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4425 LPMENUITEMINFOW lpmii)
4427 return GetMenuItemInfo_common (hmenu, item, bypos,
4428 (LPMENUITEMINFOA)lpmii, TRUE);
4431 /**********************************************************************
4432 * SetMenuItemInfo_common
4435 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4436 const MENUITEMINFOA *lpmii,
4437 BOOL unicode)
4439 if (!menu) return FALSE;
4441 if (lpmii->fMask & MIIM_TYPE ) {
4442 /* Get rid of old string. */
4443 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4444 HeapFree(SystemHeap, 0, menu->text);
4445 menu->text = NULL;
4448 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4449 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4450 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4452 menu->text = lpmii->dwTypeData;
4454 if (IS_STRING_ITEM(menu->fType) && menu->text) {
4455 if (unicode)
4456 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4457 else
4458 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4462 if (lpmii->fMask & MIIM_FTYPE ) {
4463 /* free the string when the type is changing */
4464 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4465 HeapFree(SystemHeap, 0, menu->text);
4466 menu->text = NULL;
4468 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4469 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4472 if (lpmii->fMask & MIIM_STRING ) {
4473 /* free the string when used */
4474 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4475 HeapFree(SystemHeap, 0, menu->text);
4476 if (unicode)
4477 menu->text = HEAP_strdupWtoA(SystemHeap, 0, (LPWSTR) lpmii->dwTypeData);
4478 else
4479 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4483 if (lpmii->fMask & MIIM_STATE)
4485 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4486 menu->fState = lpmii->fState;
4489 if (lpmii->fMask & MIIM_ID)
4490 menu->wID = lpmii->wID;
4492 if (lpmii->fMask & MIIM_SUBMENU) {
4493 menu->hSubMenu = lpmii->hSubMenu;
4494 if (menu->hSubMenu) {
4495 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4496 if (subMenu) {
4497 subMenu->wFlags |= MF_POPUP;
4498 menu->fType |= MF_POPUP;
4500 else
4501 /* FIXME: Return an error ? */
4502 menu->fType &= ~MF_POPUP;
4504 else
4505 menu->fType &= ~MF_POPUP;
4508 if (lpmii->fMask & MIIM_CHECKMARKS)
4510 if (lpmii->fType & MFT_RADIOCHECK)
4511 menu->fType |= MFT_RADIOCHECK;
4513 menu->hCheckBit = lpmii->hbmpChecked;
4514 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4516 if (lpmii->fMask & MIIM_DATA)
4517 menu->dwItemData = lpmii->dwItemData;
4519 debug_print_menuitem("SetMenuItemInfo_common: ", menu, "");
4520 return TRUE;
4523 /**********************************************************************
4524 * SetMenuItemInfoA (USER32.491)
4526 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4527 const MENUITEMINFOA *lpmii)
4529 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4530 lpmii, FALSE);
4533 /**********************************************************************
4534 * SetMenuItemInfoW (USER32.492)
4536 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4537 const MENUITEMINFOW *lpmii)
4539 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4540 (const MENUITEMINFOA*)lpmii, TRUE);
4543 /**********************************************************************
4544 * SetMenuDefaultItem (USER32.489)
4547 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4549 UINT i;
4550 POPUPMENU *menu;
4551 MENUITEM *item;
4553 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4555 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4557 /* reset all default-item flags */
4558 item = menu->items;
4559 for (i = 0; i < menu->nItems; i++, item++)
4561 item->fState &= ~MFS_DEFAULT;
4564 /* no default item */
4565 if ( -1 == uItem)
4567 return TRUE;
4570 item = menu->items;
4571 if ( bypos )
4573 if ( uItem >= menu->nItems ) return FALSE;
4574 item[uItem].fState |= MFS_DEFAULT;
4575 return TRUE;
4577 else
4579 for (i = 0; i < menu->nItems; i++, item++)
4581 if (item->wID == uItem)
4583 item->fState |= MFS_DEFAULT;
4584 return TRUE;
4589 return FALSE;
4592 /**********************************************************************
4593 * GetMenuDefaultItem (USER32.260)
4595 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4597 POPUPMENU *menu;
4598 MENUITEM * item;
4599 UINT i = 0;
4601 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4603 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4605 /* find default item */
4606 item = menu->items;
4608 /* empty menu */
4609 if (! item) return -1;
4611 while ( !( item->fState & MFS_DEFAULT ) )
4613 i++; item++;
4614 if (i >= menu->nItems ) return -1;
4617 /* default: don't return disabled items */
4618 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4620 /* search rekursiv when needed */
4621 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4623 UINT ret;
4624 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4625 if ( -1 != ret ) return ret;
4627 /* when item not found in submenu, return the popup item */
4629 return ( bypos ) ? i : item->wID;
4633 /*******************************************************************
4634 * InsertMenuItem16 (USER.441)
4636 * FIXME: untested
4638 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4639 const MENUITEMINFO16 *mii )
4641 MENUITEMINFOA miia;
4643 miia.cbSize = sizeof(miia);
4644 miia.fMask = mii->fMask;
4645 miia.dwTypeData = mii->dwTypeData;
4646 miia.fType = mii->fType;
4647 miia.fState = mii->fState;
4648 miia.wID = mii->wID;
4649 miia.hSubMenu = mii->hSubMenu;
4650 miia.hbmpChecked = mii->hbmpChecked;
4651 miia.hbmpUnchecked = mii->hbmpUnchecked;
4652 miia.dwItemData = mii->dwItemData;
4653 miia.cch = mii->cch;
4654 if (IS_STRING_ITEM(miia.fType))
4655 miia.dwTypeData = PTR_SEG_TO_LIN(miia.dwTypeData);
4656 return InsertMenuItemA( hmenu, pos, byposition, &miia );
4660 /**********************************************************************
4661 * InsertMenuItemA (USER32.323)
4663 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4664 const MENUITEMINFOA *lpmii)
4666 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4667 return SetMenuItemInfo_common(item, lpmii, FALSE);
4671 /**********************************************************************
4672 * InsertMenuItemW (USER32.324)
4674 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4675 const MENUITEMINFOW *lpmii)
4677 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4678 return SetMenuItemInfo_common(item, (const MENUITEMINFOA*)lpmii, TRUE);
4681 /**********************************************************************
4682 * CheckMenuRadioItem (USER32.47)
4685 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4686 UINT first, UINT last, UINT check,
4687 UINT bypos)
4689 MENUITEM *mifirst, *milast, *micheck;
4690 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4692 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4693 hMenu, first, last, check, bypos);
4695 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4696 milast = MENU_FindItem (&mlast, &last, bypos);
4697 micheck = MENU_FindItem (&mcheck, &check, bypos);
4699 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4700 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4701 micheck > milast || micheck < mifirst)
4702 return FALSE;
4704 while (mifirst <= milast)
4706 if (mifirst == micheck)
4708 mifirst->fType |= MFT_RADIOCHECK;
4709 mifirst->fState |= MFS_CHECKED;
4710 } else {
4711 mifirst->fType &= ~MFT_RADIOCHECK;
4712 mifirst->fState &= ~MFS_CHECKED;
4714 mifirst++;
4717 return TRUE;
4720 /**********************************************************************
4721 * CheckMenuRadioItem16 (not a Windows API)
4724 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4725 UINT16 first, UINT16 last, UINT16 check,
4726 BOOL16 bypos)
4728 return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4731 /**********************************************************************
4732 * GetMenuItemRect (USER32.266)
4734 * ATTENTION: Here, the returned values in rect are the screen
4735 * coordinates of the item just like if the menu was
4736 * always on the upper left side of the application.
4739 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4740 LPRECT rect)
4742 POPUPMENU *itemMenu;
4743 MENUITEM *item;
4744 HWND referenceHwnd;
4746 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4748 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4749 referenceHwnd = hwnd;
4751 if(!hwnd)
4753 itemMenu = MENU_GetMenu(hMenu);
4754 if (itemMenu == NULL)
4755 return FALSE;
4757 if(itemMenu->hWnd == 0)
4758 return FALSE;
4759 referenceHwnd = itemMenu->hWnd;
4762 if ((rect == NULL) || (item == NULL))
4763 return FALSE;
4765 *rect = item->rect;
4767 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4769 return TRUE;
4772 /**********************************************************************
4773 * GetMenuItemRect16 (USER.665)
4776 BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
4777 LPRECT16 rect)
4779 RECT r32;
4780 BOOL res;
4782 if (!rect) return FALSE;
4783 res = GetMenuItemRect (hwnd, hMenu, uItem, &r32);
4784 CONV_RECT32TO16 (&r32, rect);
4785 return res;
4788 /**********************************************************************
4789 * SetMenuInfo
4791 * FIXME
4792 * MIM_APPLYTOSUBMENUS
4793 * actually use the items to draw the menu
4795 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4797 POPUPMENU *menu;
4799 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4801 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4804 if (lpmi->fMask & MIM_BACKGROUND)
4805 menu->hbrBack = lpmi->hbrBack;
4807 if (lpmi->fMask & MIM_HELPID)
4808 menu->dwContextHelpID = lpmi->dwContextHelpID;
4810 if (lpmi->fMask & MIM_MAXHEIGHT)
4811 menu->cyMax = lpmi->cyMax;
4813 if (lpmi->fMask & MIM_MENUDATA)
4814 menu->dwMenuData = lpmi->dwMenuData;
4816 if (lpmi->fMask & MIM_STYLE)
4817 menu->dwStyle = lpmi->dwStyle;
4819 return TRUE;
4821 return FALSE;
4824 /**********************************************************************
4825 * GetMenuInfo
4827 * NOTES
4828 * win98/NT5.0
4831 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4832 { POPUPMENU *menu;
4834 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4836 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4839 if (lpmi->fMask & MIM_BACKGROUND)
4840 lpmi->hbrBack = menu->hbrBack;
4842 if (lpmi->fMask & MIM_HELPID)
4843 lpmi->dwContextHelpID = menu->dwContextHelpID;
4845 if (lpmi->fMask & MIM_MAXHEIGHT)
4846 lpmi->cyMax = menu->cyMax;
4848 if (lpmi->fMask & MIM_MENUDATA)
4849 lpmi->dwMenuData = menu->dwMenuData;
4851 if (lpmi->fMask & MIM_STYLE)
4852 lpmi->dwStyle = menu->dwStyle;
4854 return TRUE;
4856 return FALSE;
4859 /**********************************************************************
4860 * SetMenuContextHelpId16 (USER.384)
4862 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4864 return SetMenuContextHelpId( hMenu, dwContextHelpID );
4868 /**********************************************************************
4869 * SetMenuContextHelpId (USER32.488)
4871 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4873 LPPOPUPMENU menu;
4875 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4877 if ((menu = MENU_GetMenu(hMenu)))
4879 menu->dwContextHelpID = dwContextHelpID;
4880 return TRUE;
4882 return FALSE;
4885 /**********************************************************************
4886 * GetMenuContextHelpId16 (USER.385)
4888 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4890 return GetMenuContextHelpId( hMenu );
4893 /**********************************************************************
4894 * GetMenuContextHelpId (USER32.488)
4896 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4898 LPPOPUPMENU menu;
4900 TRACE("(0x%04x)\n", hMenu);
4902 if ((menu = MENU_GetMenu(hMenu)))
4904 return menu->dwContextHelpID;
4906 return 0;
4909 /**********************************************************************
4910 * MenuItemFromPoint (USER32.387)
4912 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4914 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4915 hWnd, hMenu, ptScreen.x, ptScreen.y);
4916 return 0;