Make sure that an empty string never matches a listbox entry in
[wine] / controls / menu.c
1 /*
2  * Menu functions
3  *
4  * Copyright 1993 Martin Ayotte
5  * Copyright 1994 Alexandre Julliard
6  * Copyright 1997 Morten Welinder
7  */
8
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.
13  */
14
15 #include <assert.h>
16 #include <ctype.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include "win.h"
21 #include "wine/winbase16.h"
22 #include "wine/winuser16.h"
23 #include "task.h"
24 #include "heap.h"
25 #include "menu.h"
26 #include "nonclient.h"
27 #include "user.h"
28 #include "message.h"
29 #include "resource.h"
30 #include "tweak.h"
31
32 #include "debugtools.h"
33
34 DEFAULT_DEBUG_CHANNEL(menu)
35
36
37 /* internal popup menu window messages */
38
39 #define MM_SETMENUHANDLE        (WM_USER + 0)
40 #define MM_GETMENUHANDLE        (WM_USER + 1)
41
42 /* Menu item structure */
43 typedef struct {
44     /* ----------- MENUITEMINFO Stuff ----------- */
45     UINT fType;                 /* Item type. */
46     UINT fState;                /* Item state.  */
47     UINT wID;                   /* Item id.  */
48     HMENU hSubMenu;             /* Pop-up menu.  */
49     HBITMAP hCheckBit;          /* Bitmap when checked.  */
50     HBITMAP hUnCheckBit;        /* Bitmap when unchecked.  */
51     LPSTR text;                 /* Item text or bitmap handle.  */
52     DWORD dwItemData;           /* Application defined.  */
53     DWORD dwTypeData;           /* depends on fMask */
54     HBITMAP hbmpItem;           /* bitmap in win98 style menus */
55     /* ----------- Wine stuff ----------- */
56     RECT      rect;             /* Item area (relative to menu window) */
57     UINT      xTab;             /* X position of text after Tab */
58 } MENUITEM;
59
60 /* Popup menu structure */
61 typedef struct {
62     WORD        wFlags;       /* Menu flags (MF_POPUP, MF_SYSMENU) */
63     WORD        wMagic;       /* Magic number */
64     HQUEUE16    hTaskQ;       /* Task queue for this menu */
65     WORD        Width;        /* Width of the whole menu */
66     WORD        Height;       /* Height of the whole menu */
67     WORD        nItems;       /* Number of items in the menu */
68     HWND        hWnd;         /* Window containing the menu */
69     MENUITEM    *items;       /* Array of menu items */
70     UINT        FocusedItem;  /* Currently focused item */
71     HWND        hwndOwner;    /* window receiving the messages for ownerdraw */
72     /* ------------ MENUINFO members ------ */
73     DWORD       dwStyle;        /* Extended mennu style */
74     UINT        cyMax;          /* max hight of the whole menu, 0 is screen hight */
75     HBRUSH      hbrBack;        /* brush for menu background */
76     DWORD       dwContextHelpID;
77     DWORD       dwMenuData;     /* application defined value */
78     HMENU       hSysMenuOwner;  /* Handle to the dummy sys menu holder */
79 } POPUPMENU, *LPPOPUPMENU;
80
81 /* internal flags for menu tracking */
82
83 #define TF_ENDMENU              0x0001
84 #define TF_SUSPENDPOPUP         0x0002
85 #define TF_SKIPREMOVE           0x0004
86
87 typedef struct
88 {
89     UINT        trackFlags;
90     HMENU       hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
91     HMENU       hTopMenu;     /* initial menu */
92     HWND        hOwnerWnd;    /* where notifications are sent */
93     POINT       pt;
94 } MTRACKER;
95
96 #define MENU_MAGIC   0x554d  /* 'MU' */
97 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
98
99 #define ITEM_PREV               -1
100 #define ITEM_NEXT                1
101
102   /* Internal MENU_TrackMenu() flags */
103 #define TPM_INTERNAL            0xF0000000
104 #define TPM_ENTERIDLEEX         0x80000000              /* set owner window for WM_ENTERIDLE */
105 #define TPM_BUTTONDOWN          0x40000000              /* menu was clicked before tracking */
106 #define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
107
108   /* popup menu shade thickness */
109 #define POPUP_XSHADE            4
110 #define POPUP_YSHADE            4
111
112   /* Space between 2 menu bar items */
113 #define MENU_BAR_ITEMS_SPACE 12
114
115   /* Minimum width of a tab character */
116 #define MENU_TAB_SPACE 8
117
118   /* Height of a separator item */
119 #define SEPARATOR_HEIGHT 5
120
121   /* (other menu->FocusedItem values give the position of the focused item) */
122 #define NO_SELECTED_ITEM  0xffff
123
124 #define MENU_ITEM_TYPE(flags) \
125   ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
126
127 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
128 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
129
130 #define IS_SYSTEM_MENU(menu)  \
131         (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
132
133 #define IS_SYSTEM_POPUP(menu) \
134         ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
135
136 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
137                    MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
138                    MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
139                    MF_POPUP | MF_SYSMENU | MF_HELP)
140 #define STATE_MASK (~TYPE_MASK)
141
142   /* Dimension of the menu bitmaps */
143 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
144 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
145
146 static HBITMAP hStdRadioCheck = 0;
147 static HBITMAP hStdCheck = 0;
148 static HBITMAP hStdMnArrow = 0;
149
150 /* Minimze/restore/close buttons to be inserted in menubar */
151 static HBITMAP hBmpMinimize = 0;
152 static HBITMAP hBmpMinimizeD = 0;
153 static HBITMAP hBmpMaximize = 0;
154 static HBITMAP hBmpMaximizeD = 0;
155 static HBITMAP hBmpClose = 0;
156 static HBITMAP hBmpCloseD = 0;
157
158
159 static HBRUSH   hShadeBrush = 0;
160 static HFONT    hMenuFont = 0;
161 static HFONT    hMenuFontBold = 0;
162
163 static HMENU MENU_DefSysPopup = 0;  /* Default system menu popup */
164
165 /* Use global popup window because there's no way 2 menus can
166  * be tracked at the same time.  */ 
167
168 static WND* pTopPopupWnd   = 0;
169 static UINT uSubPWndLevel = 0;
170
171   /* Flag set by EndMenu() to force an exit from menu tracking */
172 static BOOL fEndMenu = FALSE;
173
174
175 /***********************************************************************
176  *           debug_print_menuitem
177  *
178  * Print a menuitem in readable form.
179  */
180
181 #define debug_print_menuitem(pre, mp, post) \
182   if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
183
184 #define MENUOUT(text) \
185   DPRINTF("%s%s", (count++ ? "," : ""), (text))
186
187 #define MENUFLAG(bit,text) \
188   do { \
189     if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
190   } while (0)
191
192 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp, 
193                                     const char *postfix)
194 {
195     TRACE("%s ", prefix);
196     if (mp) {
197         UINT flags = mp->fType;
198         int typ = MENU_ITEM_TYPE(flags);
199         DPRINTF( "{ ID=0x%x", mp->wID);
200         if (flags & MF_POPUP)
201             DPRINTF( ", Sub=0x%x", mp->hSubMenu);
202         if (flags) {
203             int count = 0;
204             DPRINTF( ", Typ=");
205             if (typ == MFT_STRING)
206                 /* Nothing */ ;
207             else if (typ == MFT_SEPARATOR)
208                 MENUOUT("sep");
209             else if (typ == MFT_OWNERDRAW)
210                 MENUOUT("own");
211             else if (typ == MFT_BITMAP)
212                 MENUOUT("bit");
213             else
214                 MENUOUT("???");
215             flags -= typ;
216
217             MENUFLAG(MF_POPUP, "pop");
218             MENUFLAG(MFT_MENUBARBREAK, "barbrk");
219             MENUFLAG(MFT_MENUBREAK, "brk");
220             MENUFLAG(MFT_RADIOCHECK, "radio");
221             MENUFLAG(MFT_RIGHTORDER, "rorder");
222             MENUFLAG(MF_SYSMENU, "sys");
223             MENUFLAG(MFT_RIGHTJUSTIFY, "right");        /* same as MF_HELP */
224
225             if (flags)
226                 DPRINTF( "+0x%x", flags);
227         }
228         flags = mp->fState;
229         if (flags) {
230             int count = 0;
231             DPRINTF( ", State=");
232             MENUFLAG(MFS_GRAYED, "grey");
233             MENUFLAG(MFS_DEFAULT, "default");
234             MENUFLAG(MFS_DISABLED, "dis");
235             MENUFLAG(MFS_CHECKED, "check");
236             MENUFLAG(MFS_HILITE, "hi");
237             MENUFLAG(MF_USECHECKBITMAPS, "usebit");
238             MENUFLAG(MF_MOUSESELECT, "mouse");
239             if (flags)
240                 DPRINTF( "+0x%x", flags);
241         }
242         if (mp->hCheckBit)
243             DPRINTF( ", Chk=0x%x", mp->hCheckBit);
244         if (mp->hUnCheckBit)
245             DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
246
247         if (typ == MFT_STRING) {
248             if (mp->text)
249                 DPRINTF( ", Text=\"%s\"", mp->text);
250             else
251                 DPRINTF( ", Text=Null");
252         } else if (mp->text == NULL)
253             /* Nothing */ ;
254         else
255             DPRINTF( ", Text=%p", mp->text);
256         if (mp->dwItemData)
257             DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
258         DPRINTF( " }");
259     } else {
260         DPRINTF( "NULL");
261     }
262
263     DPRINTF(" %s\n", postfix);
264 }
265
266 #undef MENUOUT
267 #undef MENUFLAG
268
269 /***********************************************************************
270  *           MENU_CopySysPopup
271  *
272  * Return the default system menu.
273  */
274 static HMENU MENU_CopySysPopup(void)
275 {
276     HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
277
278     if( hMenu ) {
279         POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
280         menu->wFlags |= MF_SYSMENU | MF_POPUP;
281         SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
282     }
283     else {
284         hMenu = 0;
285         ERR("Unable to load default system menu\n" );
286     }
287
288     TRACE("returning %x.\n", hMenu );
289
290     return hMenu;
291 }
292
293 /***********************************************************************
294  *           MENU_GetTopPopupWnd()
295  *
296  * Return the locked pointer pTopPopupWnd.
297  */
298 static WND *MENU_GetTopPopupWnd()
299 {
300     return WIN_LockWndPtr(pTopPopupWnd);
301 }
302 /***********************************************************************
303  *           MENU_ReleaseTopPopupWnd()
304  *
305  * Realease the locked pointer pTopPopupWnd.
306  */
307 static void MENU_ReleaseTopPopupWnd()
308 {
309     WIN_ReleaseWndPtr(pTopPopupWnd);
310 }
311 /***********************************************************************
312  *           MENU_DestroyTopPopupWnd()
313  *
314  * Destroy the locked pointer pTopPopupWnd.
315  */
316 static void MENU_DestroyTopPopupWnd()
317 {
318     WND *tmpWnd = pTopPopupWnd;
319     pTopPopupWnd = NULL;
320     WIN_ReleaseWndPtr(tmpWnd);
321 }
322
323
324
325 /**********************************************************************
326  *           MENU_GetSysMenu
327  *
328  * Create a copy of the system menu. System menu in Windows is
329  * a special menu-bar with the single entry - system menu popup.
330  * This popup is presented to the outside world as a "system menu". 
331  * However, the real system menu handle is sometimes seen in the 
332  * WM_MENUSELECT paramemters (and Word 6 likes it this way).
333  */
334 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
335 {
336     HMENU hMenu;
337
338     if ((hMenu = CreateMenu()))
339     {
340         POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
341         menu->wFlags = MF_SYSMENU;
342         menu->hWnd = hWnd;
343
344         if (hPopupMenu == (HMENU)(-1))
345             hPopupMenu = MENU_CopySysPopup();
346         else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup; 
347
348         if (hPopupMenu)
349         {
350             InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
351
352             menu->items[0].fType = MF_SYSMENU | MF_POPUP;
353             menu->items[0].fState = 0;
354             menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
355             menu->wFlags |= MF_SYSMENU;
356
357             TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
358             return hMenu;
359         }
360         DestroyMenu( hMenu );
361     }
362     ERR("failed to load system menu!\n");
363     return 0;
364 }
365
366
367 /***********************************************************************
368  *           MENU_Init
369  *
370  * Menus initialisation.
371  */
372 BOOL MENU_Init()
373 {
374     HBITMAP hBitmap;
375     NONCLIENTMETRICSA ncm;
376
377     static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
378                                             0x55, 0, 0xAA, 0,
379                                             0x55, 0, 0xAA, 0,
380                                             0x55, 0, 0xAA, 0 };
381
382     /* Load menu bitmaps */
383     hStdCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK));
384     hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK));
385     hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
386     /* Load system buttons bitmaps */
387     hBmpMinimize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE));
388     hBmpMinimizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED));
389     hBmpMaximize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE));
390     hBmpMaximizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED));
391     hBmpClose = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE));
392     hBmpCloseD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED));
393
394     if (hStdCheck)
395     {
396         BITMAP bm;
397         GetObjectA( hStdCheck, sizeof(bm), &bm );
398         check_bitmap_width = bm.bmWidth;
399         check_bitmap_height = bm.bmHeight;
400     } else
401          return FALSE;
402
403     /* Assume that radio checks have the same size as regular check.  */
404     if (!hStdRadioCheck)
405          return FALSE;
406
407     if (hStdMnArrow)
408     {
409         BITMAP bm;
410         GetObjectA( hStdMnArrow, sizeof(bm), &bm );
411         arrow_bitmap_width = bm.bmWidth;
412         arrow_bitmap_height = bm.bmHeight;
413     } else
414         return FALSE;
415
416     if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits))) 
417         return FALSE;
418
419     if(!(hShadeBrush = CreatePatternBrush( hBitmap ))) 
420         return FALSE;
421         
422     DeleteObject( hBitmap );
423     if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
424         return FALSE;
425
426     ncm.cbSize = sizeof (NONCLIENTMETRICSA);
427     if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
428         return FALSE;
429         
430     if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
431         return FALSE;
432
433     ncm.lfMenuFont.lfWeight += 300;
434     if ( ncm.lfMenuFont.lfWeight > 1000)
435         ncm.lfMenuFont.lfWeight = 1000;
436
437     if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
438         return FALSE;
439
440     return TRUE;
441 }
442
443 /***********************************************************************
444  *           MENU_InitSysMenuPopup
445  *
446  * Grey the appropriate items in System menu.
447  */
448 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
449 {
450     BOOL gray;
451
452     gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
453     EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
454     gray = ((style & WS_MAXIMIZE) != 0);
455     EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
456     gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
457     EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
458     gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
459     EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
460     gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
461     EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
462     gray = (clsStyle & CS_NOCLOSE) != 0;
463
464     /* The menu item must keep its state if it's disabled */
465     if(gray)
466         EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
467 }
468
469
470 /******************************************************************************
471  *
472  *   UINT32  MENU_GetStartOfNextColumn(
473  *     HMENU32  hMenu )
474  *
475  *****************************************************************************/
476
477 static UINT  MENU_GetStartOfNextColumn(
478     HMENU  hMenu )
479 {
480     POPUPMENU  *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
481     UINT  i = menu->FocusedItem + 1;
482
483     if(!menu)
484         return NO_SELECTED_ITEM;
485
486     if( i == NO_SELECTED_ITEM )
487         return i;
488
489     for( ; i < menu->nItems; ++i ) {
490         if (menu->items[i].fType & MF_MENUBARBREAK)
491             return i;
492     }
493
494     return NO_SELECTED_ITEM;
495 }
496
497
498 /******************************************************************************
499  *
500  *   UINT32  MENU_GetStartOfPrevColumn(
501  *     HMENU32  hMenu )
502  *
503  *****************************************************************************/
504
505 static UINT  MENU_GetStartOfPrevColumn(
506     HMENU  hMenu )
507 {
508     POPUPMENU const  *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
509     UINT  i;
510
511     if( !menu )
512         return NO_SELECTED_ITEM;
513
514     if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
515         return NO_SELECTED_ITEM;
516
517     /* Find the start of the column */
518
519     for(i = menu->FocusedItem; i != 0 &&
520          !(menu->items[i].fType & MF_MENUBARBREAK);
521         --i); /* empty */
522
523     if(i == 0)
524         return NO_SELECTED_ITEM;
525
526     for(--i; i != 0; --i) {
527         if (menu->items[i].fType & MF_MENUBARBREAK)
528             break;
529     }
530
531     TRACE("ret %d.\n", i );
532
533     return i;
534 }
535
536
537
538 /***********************************************************************
539  *           MENU_FindItem
540  *
541  * Find a menu item. Return a pointer on the item, and modifies *hmenu
542  * in case the item was in a sub-menu.
543  */
544 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
545 {
546     POPUPMENU *menu;
547     UINT i;
548
549     if (((*hmenu)==0xffff) || (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu)))) return NULL;
550     if (wFlags & MF_BYPOSITION)
551     {
552         if (*nPos >= menu->nItems) return NULL;
553         return &menu->items[*nPos];
554     }
555     else
556     {
557         MENUITEM *item = menu->items;
558         for (i = 0; i < menu->nItems; i++, item++)
559         {
560             if (item->wID == *nPos)
561             {
562                 *nPos = i;
563                 return item;
564             }
565             else if (item->fType & MF_POPUP)
566             {
567                 HMENU hsubmenu = item->hSubMenu;
568                 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
569                 if (subitem)
570                 {
571                     *hmenu = hsubmenu;
572                     return subitem;
573                 }
574             }
575         }
576     }
577     return NULL;
578 }
579
580 /***********************************************************************
581  *           MENU_FreeItemData
582  */
583 static void MENU_FreeItemData( MENUITEM* item )
584 {
585     /* delete text */
586     if (IS_STRING_ITEM(item->fType) && item->text)
587         HeapFree( SystemHeap, 0, item->text );
588 }
589
590 /***********************************************************************
591  *           MENU_FindItemByCoords
592  *
593  * Find the item at the specified coordinates (screen coords). Does 
594  * not work for child windows and therefore should not be called for 
595  * an arbitrary system menu.
596  */
597 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, 
598                                         POINT pt, UINT *pos )
599 {
600     MENUITEM *item;
601     UINT i;
602     RECT wrect;
603
604     if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
605     pt.x -= wrect.left;pt.y -= wrect.top;
606     item = menu->items;
607     for (i = 0; i < menu->nItems; i++, item++)
608     {
609         if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
610             (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
611         {
612             if (pos) *pos = i;
613             return item;
614         }
615     }
616     return NULL;
617 }
618
619
620 /***********************************************************************
621  *           MENU_FindItemByKey
622  *
623  * Find the menu item selected by a key press.
624  * Return item id, -1 if none, -2 if we should close the menu.
625  */
626 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, 
627                                   UINT key, BOOL forceMenuChar )
628 {
629     TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
630
631     if (!IsMenu( hmenu )) 
632     {
633         WND* w = WIN_FindWndPtr(hwndOwner);
634         hmenu = GetSubMenu(w->hSysMenu, 0);
635         WIN_ReleaseWndPtr(w);
636     }
637
638     if (hmenu)
639     {
640         POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
641         MENUITEM *item = menu->items;
642         LONG menuchar;
643
644         if( !forceMenuChar )
645         {
646              UINT i;
647
648              key = toupper(key);
649              for (i = 0; i < menu->nItems; i++, item++)
650              {
651                 if (item->text && (IS_STRING_ITEM(item->fType)))
652                 {
653                     char *p = item->text - 2;
654                     do
655                     {
656                         p = strchr (p + 2, '&');
657                     }
658                     while (p != NULL && p [1] == '&');
659                     if (p && (toupper(p[1]) == key)) return i;
660                 }
661              }
662         }
663         menuchar = SendMessageA( hwndOwner, WM_MENUCHAR, 
664                                    MAKEWPARAM( key, menu->wFlags ), hmenu );
665         if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
666         if (HIWORD(menuchar) == 1) return (UINT)(-2);
667     }
668     return (UINT)(-1);
669 }
670 /***********************************************************************
671  *           MENU_LoadMagicItem
672  *
673  * Load the bitmap associated with the magic menu item and its style
674  */
675
676 static HBITMAP MENU_LoadMagicItem(UINT id, BOOL hilite, DWORD dwItemData)
677 {
678     /*
679      * Magic menu item id's section
680      * These magic id's are used by windows to insert "standard" mdi
681      * buttons (minimize,restore,close) on menu. Under windows,
682      * these magic id's make sure the right things appear when those
683      * bitmap buttons are pressed/selected/released.
684      */
685
686     switch(id & 0xffff)
687     {   case HBMMENU_SYSTEM:
688             return (dwItemData) ?
689                 (HBITMAP)dwItemData :
690                 (hilite ? hBmpMinimizeD : hBmpMinimize);
691         case HBMMENU_MBAR_RESTORE:
692             return (hilite ? hBmpMaximizeD: hBmpMaximize);
693         case HBMMENU_MBAR_MINIMIZE:
694             return (hilite ? hBmpMinimizeD : hBmpMinimize);
695         case HBMMENU_MBAR_CLOSE:
696             return (hilite ? hBmpCloseD : hBmpClose);
697         case HBMMENU_CALLBACK:
698         case HBMMENU_MBAR_CLOSE_D:
699         case HBMMENU_MBAR_MINIMIZE_D:
700         case HBMMENU_POPUP_CLOSE:
701         case HBMMENU_POPUP_RESTORE:
702         case HBMMENU_POPUP_MAXIMIZE:
703         case HBMMENU_POPUP_MINIMIZE:
704         default:
705             FIXME("Magic 0x%08x not implemented\n", id);
706             return 0;
707     }
708
709 }
710
711 /***********************************************************************
712  *           MENU_CalcItemSize
713  *
714  * Calculate the size of the menu item and store it in lpitem->rect.
715  */
716 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
717                                INT orgX, INT orgY, BOOL menuBar )
718 {
719     char *p;
720
721     TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
722     debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem, 
723                          (menuBar ? " (MenuBar)" : ""));
724
725     SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
726
727     if (lpitem->fType & MF_OWNERDRAW)
728     {
729         MEASUREITEMSTRUCT mis;
730         mis.CtlType    = ODT_MENU;
731         mis.CtlID      = 0;
732         mis.itemID     = lpitem->wID;
733         mis.itemData   = (DWORD)lpitem->dwItemData;
734         mis.itemHeight = 0;
735         mis.itemWidth  = 0;
736         SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
737         lpitem->rect.bottom += mis.itemHeight;
738         lpitem->rect.right  += mis.itemWidth;
739         TRACE("id=%04x size=%dx%d\n",
740                      lpitem->wID, mis.itemWidth, mis.itemHeight);
741         return;
742     } 
743
744     if (lpitem->fType & MF_SEPARATOR)
745     {
746         lpitem->rect.bottom += SEPARATOR_HEIGHT;
747         return;
748     }
749
750     if (!menuBar)
751     {
752         lpitem->rect.right += 2 * check_bitmap_width;
753         if (lpitem->fType & MF_POPUP)
754             lpitem->rect.right += arrow_bitmap_width;
755     }
756
757     if (IS_BITMAP_ITEM(lpitem->fType))
758     {
759         BITMAP bm;
760         HBITMAP resBmp = 0;
761
762         /* Check if there is a magic menu item associated with this item */
763         if((LOWORD((int)lpitem->text))<12)
764         {
765             resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fType & MF_HILITE),
766                                         lpitem->dwItemData);
767         }
768         else
769             resBmp = (HBITMAP)lpitem->text;
770
771         if (GetObjectA(resBmp, sizeof(bm), &bm ))
772         {
773             lpitem->rect.right  += bm.bmWidth;
774             lpitem->rect.bottom += bm.bmHeight;
775
776         }
777     }
778     
779
780     /* If we get here, then it must be a text item */
781     if (IS_STRING_ITEM( lpitem->fType ))
782     {   SIZE size;
783
784         GetTextExtentPoint32A(hdc, lpitem->text,  strlen(lpitem->text), &size);
785         
786         lpitem->rect.right  += size.cx;
787         if (TWEAK_WineLook == WIN31_LOOK)
788             lpitem->rect.bottom += MAX( size.cy, GetSystemMetrics(SM_CYMENU) );
789         else
790             lpitem->rect.bottom += MAX (size.cy, GetSystemMetrics(SM_CYMENU)-1);
791         lpitem->xTab = 0;
792
793         if (menuBar)
794         {
795              lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
796         }
797         else if ((p = strchr( lpitem->text, '\t' )) != NULL)
798         {
799             /* Item contains a tab (only meaningful in popup menus) */
800             GetTextExtentPoint32A(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
801             lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
802             lpitem->rect.right += MENU_TAB_SPACE;
803         }
804         else
805         {
806             if (strchr( lpitem->text, '\b' ))
807                 lpitem->rect.right += MENU_TAB_SPACE;
808             lpitem->xTab = lpitem->rect.right - check_bitmap_width 
809                            - arrow_bitmap_width;
810         }
811     }
812     TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
813 }
814
815
816 /***********************************************************************
817  *           MENU_PopupMenuCalcSize
818  *
819  * Calculate the size of a popup menu.
820  */
821 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
822 {
823     MENUITEM *lpitem;
824     HDC hdc;
825     int start, i;
826     int orgX, orgY, maxX, maxTab, maxTabWidth;
827
828     lppop->Width = lppop->Height = 0;
829     if (lppop->nItems == 0) return;
830     hdc = GetDC( 0 );
831
832     SelectObject( hdc, hMenuFont);
833     
834     start = 0;
835     maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2 ;
836
837     while (start < lppop->nItems)
838     {
839         lpitem = &lppop->items[start];
840         orgX = maxX;
841         orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
842
843         maxTab = maxTabWidth = 0;
844
845           /* Parse items until column break or end of menu */
846         for (i = start; i < lppop->nItems; i++, lpitem++)
847         {
848             if ((i != start) &&
849                 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
850
851             MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
852
853             if (lpitem->fType & MF_MENUBARBREAK) orgX++;
854             maxX = MAX( maxX, lpitem->rect.right );
855             orgY = lpitem->rect.bottom;
856             if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
857             {
858                 maxTab = MAX( maxTab, lpitem->xTab );
859                 maxTabWidth = MAX(maxTabWidth,lpitem->rect.right-lpitem->xTab);
860             }
861         }
862
863           /* Finish the column (set all items to the largest width found) */
864         maxX = MAX( maxX, maxTab + maxTabWidth );
865         for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
866         {
867             lpitem->rect.right = maxX;
868             if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
869                 lpitem->xTab = maxTab;
870         
871         }
872         lppop->Height = MAX( lppop->Height, orgY );
873     }
874
875     lppop->Width  = maxX;
876
877     /* space for 3d border */
878     if(TWEAK_WineLook > WIN31_LOOK)
879     {
880         lppop->Height += 2;
881         lppop->Width += 2;
882     }
883
884     ReleaseDC( 0, hdc );
885 }
886
887
888 /***********************************************************************
889  *           MENU_MenuBarCalcSize
890  *
891  * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
892  * height is off by 1 pixel which causes lengthy window relocations when
893  * active document window is maximized/restored.
894  *
895  * Calculate the size of the menu bar.
896  */
897 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
898                                   LPPOPUPMENU lppop, HWND hwndOwner )
899 {
900     MENUITEM *lpitem;
901     int start, i, orgX, orgY, maxY, helpPos;
902
903     if ((lprect == NULL) || (lppop == NULL)) return;
904     if (lppop->nItems == 0) return;
905     TRACE("left=%d top=%d right=%d bottom=%d\n", 
906                  lprect->left, lprect->top, lprect->right, lprect->bottom);
907     lppop->Width  = lprect->right - lprect->left;
908     lppop->Height = 0;
909     maxY = lprect->top;
910     start = 0;
911     helpPos = -1;
912     while (start < lppop->nItems)
913     {
914         lpitem = &lppop->items[start];
915         orgX = lprect->left;
916         orgY = maxY;
917
918           /* Parse items until line break or end of menu */
919         for (i = start; i < lppop->nItems; i++, lpitem++)
920         {
921             if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i;
922             if ((i != start) &&
923                 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
924
925             TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", 
926                          orgX, orgY );
927             debug_print_menuitem ("  item: ", lpitem, "");
928             MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
929
930             if (lpitem->rect.right > lprect->right)
931             {
932                 if (i != start) break;
933                 else lpitem->rect.right = lprect->right;
934             }
935             maxY = MAX( maxY, lpitem->rect.bottom );
936             orgX = lpitem->rect.right;
937         }
938
939           /* Finish the line (set all items to the largest height found) */
940         while (start < i) lppop->items[start++].rect.bottom = maxY;
941     }
942
943     lprect->bottom = maxY;
944     lppop->Height = lprect->bottom - lprect->top;
945
946     /* Flush right all magic items and items between the MF_HELP and */
947     /* the last item (if several lines, only move the last line) */
948     lpitem = &lppop->items[lppop->nItems-1];
949     orgY = lpitem->rect.top;
950     orgX = lprect->right;
951     for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
952     {
953         if ( !IS_BITMAP_ITEM(lpitem->fType) && ((helpPos ==-1) ? TRUE : (helpPos>i) ))
954             break;                              /* done */
955         if (lpitem->rect.top != orgY) break;    /* Other line */
956         if (lpitem->rect.right >= orgX) break;  /* Too far right already */
957         lpitem->rect.left += orgX - lpitem->rect.right;
958         lpitem->rect.right = orgX;
959         orgX = lpitem->rect.left;
960     }
961 }
962
963 /***********************************************************************
964  *           MENU_DrawMenuItem
965  *
966  * Draw a single menu item.
967  */
968 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
969                                UINT height, BOOL menuBar, UINT odaction )
970 {
971     RECT rect;
972
973     debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
974
975     if (lpitem->fType & MF_SYSMENU)
976     {
977         if( !IsIconic(hwnd) ) {
978             if (TWEAK_WineLook > WIN31_LOOK)
979                 NC_DrawSysButton95( hwnd, hdc,
980                                     lpitem->fState &
981                                     (MF_HILITE | MF_MOUSESELECT) );
982             else
983                 NC_DrawSysButton( hwnd, hdc, 
984                                   lpitem->fState &
985                                   (MF_HILITE | MF_MOUSESELECT) );
986         }
987
988         return;
989     }
990
991     if (lpitem->fType & MF_OWNERDRAW)
992     {
993         DRAWITEMSTRUCT dis;
994
995         dis.CtlType   = ODT_MENU;
996         dis.CtlID     = 0;
997         dis.itemID    = lpitem->wID;
998         dis.itemData  = (DWORD)lpitem->dwItemData;
999         dis.itemState = 0;
1000         if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1001         if (lpitem->fState & MF_GRAYED)  dis.itemState |= ODS_GRAYED;
1002         if (lpitem->fState & MF_HILITE)  dis.itemState |= ODS_SELECTED;
1003         dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1004         dis.hwndItem   = hmenu;
1005         dis.hDC        = hdc;
1006         dis.rcItem     = lpitem->rect;
1007         TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1008               "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
1009               dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, 
1010               dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1011               dis.rcItem.bottom);
1012         SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1013         return;
1014     }
1015
1016     TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
1017                                         lpitem->rect.right,lpitem->rect.bottom);
1018
1019     if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1020
1021     rect = lpitem->rect;
1022
1023     if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)))
1024         if ((menuBar) &&  (TWEAK_WineLook==WIN98_LOOK))
1025             DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1026         else
1027             FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
1028     else
1029         FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1030
1031     SetBkMode( hdc, TRANSPARENT );
1032
1033     /* vertical separator */
1034     if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1035     {
1036         if (TWEAK_WineLook > WIN31_LOOK) 
1037         {
1038             RECT rc = rect;
1039             rc.top = 3;
1040             rc.bottom = height - 3;
1041             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1042         }
1043         else 
1044         {
1045             SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1046             MoveTo16( hdc, rect.left, 0 );
1047             LineTo( hdc, rect.left, height );
1048         }
1049     }
1050
1051     /* horizontal separator */
1052     if (lpitem->fType & MF_SEPARATOR)
1053     {
1054         if (TWEAK_WineLook > WIN31_LOOK) 
1055         {
1056             RECT rc = rect;
1057             rc.left++;
1058             rc.right--;
1059             rc.top += SEPARATOR_HEIGHT / 2;
1060             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1061         }
1062         else 
1063         {
1064             SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1065             MoveTo16( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
1066             LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1067         }
1068         return;
1069     }
1070
1071       /* Setup colors */
1072
1073     if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)) )
1074     {
1075         if (lpitem->fState & MF_GRAYED)
1076             SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1077         else
1078             SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
1079         SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
1080     }
1081     else
1082     {
1083         if (lpitem->fState & MF_GRAYED)
1084             SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1085         else
1086             SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1087         SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1088     }
1089
1090         /* helper lines for debugging */
1091 /*      FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1092         SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1093         MoveTo16( hdc, rect.left, (rect.top + rect.bottom)/2 );
1094         LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1095 */
1096
1097     if (!menuBar)
1098     {
1099         INT     y = rect.top + rect.bottom;
1100
1101           /* Draw the check mark
1102            *
1103            * FIXME:
1104            * Custom checkmark bitmaps are monochrome but not always 1bpp. 
1105            */
1106
1107         if (lpitem->fState & MF_CHECKED)
1108         {
1109             HBITMAP bm = lpitem->hCheckBit ? lpitem->hCheckBit :
1110                         ((lpitem->fType & MFT_RADIOCHECK) ? hStdRadioCheck : hStdCheck);
1111             HDC hdcMem = CreateCompatibleDC( hdc );
1112
1113             SelectObject( hdcMem, bm );
1114             BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1115                       check_bitmap_width, check_bitmap_height,
1116                       hdcMem, 0, 0, SRCCOPY );
1117             DeleteDC( hdcMem );
1118         } 
1119         else if (lpitem->hUnCheckBit) 
1120         {
1121             HDC hdcMem = CreateCompatibleDC( hdc );
1122
1123             SelectObject( hdcMem, lpitem->hUnCheckBit );
1124             BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1125                       check_bitmap_width, check_bitmap_height,
1126                       hdcMem, 0, 0, SRCCOPY );
1127             DeleteDC( hdcMem );
1128         }
1129         
1130           /* Draw the popup-menu arrow */
1131         if (lpitem->fType & MF_POPUP)
1132         {
1133             HDC hdcMem = CreateCompatibleDC( hdc );
1134
1135             SelectObject( hdcMem, hStdMnArrow );
1136             BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1137                       (y - arrow_bitmap_height) / 2,
1138                       arrow_bitmap_width, arrow_bitmap_height,
1139                       hdcMem, 0, 0, SRCCOPY );
1140             DeleteDC( hdcMem );
1141         }
1142
1143         rect.left += check_bitmap_width;
1144         rect.right -= arrow_bitmap_width;
1145     }
1146
1147     /* Draw the item text or bitmap */
1148     if (IS_BITMAP_ITEM(lpitem->fType))
1149     {   int top;
1150
1151         HBITMAP resBmp = 0;
1152
1153         HDC hdcMem = CreateCompatibleDC( hdc );
1154
1155         /*
1156          * Check if there is a magic menu item associated with this item
1157          * and load the appropriate bitmap
1158          */
1159         if((LOWORD((int)lpitem->text)) < 12)
1160         {
1161             resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fState & MF_HILITE),
1162                                         lpitem->dwItemData);
1163         }
1164         else
1165             resBmp = (HBITMAP)lpitem->text;
1166
1167         if (resBmp)
1168         {
1169             BITMAP bm;
1170             GetObjectA( resBmp, sizeof(bm), &bm );
1171         
1172             SelectObject(hdcMem,resBmp );
1173         
1174             /* handle fontsize >  bitmap_height */
1175             top = ((rect.bottom-rect.top)>bm.bmHeight) ? 
1176                 rect.top+(rect.bottom-rect.top-bm.bmHeight)/2 : rect.top;
1177
1178             BitBlt( hdc, rect.left, top, rect.right - rect.left,
1179                   rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY );
1180         }
1181         DeleteDC( hdcMem );
1182
1183         return;
1184
1185     }
1186     /* No bitmap - process text if present */
1187     else if (IS_STRING_ITEM(lpitem->fType))
1188     {
1189         register int i;
1190         HFONT hfontOld = 0;
1191         
1192         UINT uFormat = (menuBar) ?
1193                         DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1194                         DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1195
1196         if ( lpitem->fState & MFS_DEFAULT )
1197         {
1198              hfontOld = SelectObject( hdc, hMenuFontBold);
1199         }
1200
1201         if (menuBar)
1202         {
1203             rect.left += MENU_BAR_ITEMS_SPACE / 2;
1204             rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1205             i = strlen( lpitem->text );
1206         }
1207         else
1208         {
1209             for (i = 0; lpitem->text[i]; i++)
1210                 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1211                     break;
1212         }
1213
1214         if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1215         {
1216             if (!(lpitem->fState & MF_HILITE) )
1217             {
1218                 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1219                 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1220                 DrawTextA( hdc, lpitem->text, i, &rect, uFormat );
1221                 --rect.left; --rect.top; --rect.right; --rect.bottom;
1222             }
1223             SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1224         }
1225         
1226         DrawTextA( hdc, lpitem->text, i, &rect, uFormat);
1227
1228         /* paint the shortcut text */
1229         if (lpitem->text[i])  /* There's a tab or flush-right char */
1230         {
1231             if (lpitem->text[i] == '\t')
1232             {
1233                 rect.left = lpitem->xTab;
1234                 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1235             }
1236             else 
1237             {
1238                 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1239             }
1240
1241             if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1242             {
1243                 if (!(lpitem->fState & MF_HILITE) )
1244                 {
1245                     ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1246                     SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1247                     DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1248                     --rect.left; --rect.top; --rect.right; --rect.bottom;
1249                 }
1250                 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1251             }
1252             DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1253         }
1254
1255         if (hfontOld) 
1256             SelectObject (hdc, hfontOld);
1257     }
1258 }
1259
1260
1261 /***********************************************************************
1262  *           MENU_DrawPopupMenu
1263  *
1264  * Paint a popup menu.
1265  */
1266 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1267 {
1268     HBRUSH hPrevBrush = 0;
1269     RECT rect;
1270
1271     TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1272
1273     GetClientRect( hwnd, &rect );
1274
1275     if(TWEAK_WineLook == WIN31_LOOK) 
1276     {
1277         rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1278         rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1279     } 
1280
1281     if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) )) 
1282         && (SelectObject( hdc, hMenuFont)))
1283     {
1284         HPEN hPrevPen;
1285         
1286         Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1287
1288         hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1289         if( hPrevPen )
1290         {
1291             INT ropPrev, i;
1292             POPUPMENU *menu;
1293
1294             /* draw 3-d shade */
1295             if(TWEAK_WineLook == WIN31_LOOK) {
1296                 SelectObject( hdc, hShadeBrush );
1297                 SetBkMode( hdc, TRANSPARENT );
1298                 ropPrev = SetROP2( hdc, R2_MASKPEN );
1299
1300                 i = rect.right;         /* why SetBrushOrg() doesn't? */
1301                 PatBlt( hdc, i & 0xfffffffe,
1302                           rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1303                           i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1304                           rect.bottom - rect.top, 0x00a000c9 );
1305                 i = rect.bottom;
1306                 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1307                           i & 0xfffffffe,rect.right - rect.left,
1308                           i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1309                 SelectObject( hdc, hPrevPen );
1310                 SelectObject( hdc, hPrevBrush );
1311                 SetROP2( hdc, ropPrev );
1312             }
1313             else
1314                 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1315
1316             /* draw menu items */
1317
1318             menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1319             if (menu && menu->nItems)
1320             {
1321                 MENUITEM *item;
1322                 UINT u;
1323
1324                 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1325                     MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item, 
1326                                        menu->Height, FALSE, ODA_DRAWENTIRE );
1327
1328             }
1329         } else 
1330         {
1331             SelectObject( hdc, hPrevBrush );
1332         }
1333     }
1334 }
1335
1336 /***********************************************************************
1337  *           MENU_DrawMenuBar
1338  *
1339  * Paint a menu bar. Returns the height of the menu bar.
1340  * called from [windows/nonclient.c]
1341  */
1342 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1343                          BOOL suppress_draw)
1344 {
1345     LPPOPUPMENU lppop;
1346     UINT i,retvalue;
1347     HFONT hfontOld = 0;
1348
1349     WND *wndPtr = WIN_FindWndPtr( hwnd );
1350     
1351     lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( (HMENU)wndPtr->wIDmenu );
1352     if (lppop == NULL || lprect == NULL)
1353     {
1354         retvalue = GetSystemMetrics(SM_CYMENU);
1355         goto END;
1356     }
1357
1358     TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1359
1360     hfontOld = SelectObject( hDC, hMenuFont);
1361
1362     if (lppop->Height == 0)
1363         MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1364
1365     lprect->bottom = lprect->top + lppop->Height;
1366
1367     if (suppress_draw)
1368     {
1369         retvalue = lppop->Height;
1370         goto END;
1371     }
1372
1373     FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1374
1375     if (TWEAK_WineLook == WIN31_LOOK) 
1376     {
1377         SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1378         MoveTo16( hDC, lprect->left, lprect->bottom );
1379         LineTo( hDC, lprect->right, lprect->bottom );
1380     }
1381     else 
1382     {
1383         SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1384         MoveTo16( hDC, lprect->left, lprect->bottom );
1385         LineTo( hDC, lprect->right, lprect->bottom );
1386     }
1387
1388     if (lppop->nItems == 0)
1389     {
1390         retvalue = GetSystemMetrics(SM_CYMENU);
1391         goto END;
1392     }
1393
1394     for (i = 0; i < lppop->nItems; i++)
1395     {
1396         MENU_DrawMenuItem( hwnd, (HMENU)wndPtr->wIDmenu, GetWindow(hwnd,GW_OWNER),
1397                          hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
1398     }
1399     retvalue = lppop->Height;
1400
1401 END:
1402     if (hfontOld) 
1403         SelectObject (hDC, hfontOld);
1404         
1405     WIN_ReleaseWndPtr(wndPtr);
1406     return retvalue;
1407
1408
1409 /***********************************************************************
1410  *           MENU_PatchResidentPopup
1411  */
1412 BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
1413 {
1414     WND *pTPWnd = MENU_GetTopPopupWnd();
1415     
1416     if( pTPWnd )
1417     {
1418         HTASK16 hTask = 0;
1419
1420         TRACE("patching resident popup: %04x %04x [%04x %04x]\n", 
1421                 checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTPWnd->hmemTaskQ,
1422                 pTPWnd->owner ? pTPWnd->owner->hwndSelf : 0);
1423
1424         switch( checkQueue )
1425         {
1426             case 0: /* checkWnd is the new popup owner */
1427                  if( checkWnd )
1428                  {
1429                      pTPWnd->owner = checkWnd;
1430                      if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
1431                          hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
1432                  }
1433                  break;
1434
1435             case 0xFFFF: /* checkWnd is destroyed */
1436                  if( pTPWnd->owner == checkWnd )
1437                      pTPWnd->owner = NULL;
1438                  MENU_ReleaseTopPopupWnd();
1439                  return TRUE; 
1440
1441             default: /* checkQueue is exiting */
1442                  if( pTPWnd->hmemTaskQ == checkQueue )
1443                  {
1444                      hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
1445                      hTask = TASK_GetNextTask( hTask );
1446                  }
1447                  break;
1448         }
1449
1450         if( hTask )
1451         {
1452             TDB* task = (TDB*)GlobalLock16( hTask );
1453             if( task )
1454             {
1455                 pTPWnd->hInstance = task->hInstance;
1456                 pTPWnd->hmemTaskQ = task->hQueue;
1457                 MENU_ReleaseTopPopupWnd();
1458                 return TRUE;
1459             } 
1460             else WARN("failed to patch resident popup.\n");
1461         } 
1462     }
1463     MENU_ReleaseTopPopupWnd();
1464     return FALSE;
1465 }
1466
1467 /***********************************************************************
1468  *           MENU_ShowPopup
1469  *
1470  * Display a popup menu.
1471  */
1472 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1473                               INT x, INT y, INT xanchor, INT yanchor )
1474 {
1475     POPUPMENU   *menu;
1476     WND         *wndOwner = NULL;
1477
1478     TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1479     hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1480
1481     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
1482     if (menu->FocusedItem != NO_SELECTED_ITEM)
1483     {
1484         menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1485         menu->FocusedItem = NO_SELECTED_ITEM;
1486     }
1487
1488     /* store the owner for DrawItem*/
1489     menu->hwndOwner = hwndOwner;
1490
1491     if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
1492     {
1493         UINT    width, height;
1494
1495         MENU_PopupMenuCalcSize( menu, hwndOwner );
1496
1497         /* adjust popup menu pos so that it fits within the desktop */
1498
1499         width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1500         height = menu->Height + GetSystemMetrics(SM_CYBORDER); 
1501
1502         if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1503         {
1504             if( xanchor )
1505                 x -= width - xanchor;
1506             if( x + width > GetSystemMetrics(SM_CXSCREEN))
1507                 x = GetSystemMetrics(SM_CXSCREEN) - width;
1508         }
1509         if( x < 0 ) x = 0;
1510
1511         if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1512         { 
1513             if( yanchor )
1514                 y -= height + yanchor;
1515             if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1516                 y = GetSystemMetrics(SM_CYSCREEN) - height;
1517         }
1518         if( y < 0 ) y = 0;
1519
1520         if( TWEAK_WineLook == WIN31_LOOK )
1521         {
1522             width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);      /* add space for shading */
1523             height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1524         }
1525
1526         /* NOTE: In Windows, top menu popup is not owned. */
1527         if (!pTopPopupWnd)      /* create top level popup menu window */
1528         {
1529             assert( uSubPWndLevel == 0 );
1530
1531             pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1532                                           WS_POPUP, x, y, width, height,
1533                                           hwndOwner, 0, wndOwner->hInstance,
1534                                           (LPVOID)hmenu ));
1535             if (!pTopPopupWnd)
1536             {
1537                 WIN_ReleaseWndPtr(wndOwner);
1538                 return FALSE;
1539             }
1540             menu->hWnd = pTopPopupWnd->hwndSelf;
1541             MENU_ReleaseTopPopupWnd();
1542         } 
1543         else
1544             if( uSubPWndLevel )
1545             {
1546                 /* create a new window for the submenu */
1547
1548                 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1549                                           WS_POPUP, x, y, width, height,
1550                                           hwndOwner, 0, wndOwner->hInstance,
1551                                           (LPVOID)hmenu );
1552                 if( !menu->hWnd )
1553                 {
1554                     WIN_ReleaseWndPtr(wndOwner);
1555                     return FALSE;
1556                 }
1557             }
1558             else /* top level popup menu window already exists */
1559             {
1560                 WND *pTPWnd = MENU_GetTopPopupWnd();
1561                 menu->hWnd = pTPWnd->hwndSelf;
1562
1563                 MENU_PatchResidentPopup( 0, wndOwner );
1564                 SendMessageA( pTPWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);
1565
1566                 /* adjust its size */
1567
1568                 SetWindowPos( menu->hWnd, 0, x, y, width, height,
1569                                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
1570                 MENU_ReleaseTopPopupWnd();
1571             }
1572
1573         uSubPWndLevel++;        /* menu level counter */
1574
1575       /* Display the window */
1576
1577         SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1578                         SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1579         UpdateWindow( menu->hWnd );
1580         WIN_ReleaseWndPtr(wndOwner);
1581         return TRUE;
1582     }
1583     return FALSE;
1584 }
1585
1586
1587 /***********************************************************************
1588  *           MENU_SelectItem
1589  */
1590 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1591                              BOOL sendMenuSelect )
1592 {
1593     LPPOPUPMENU lppop;
1594     HDC hdc;
1595
1596     TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1597
1598     lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1599     if (!lppop->nItems) return;
1600
1601     if ((wIndex != NO_SELECTED_ITEM) && 
1602         (lppop->items[wIndex].fType & MF_SEPARATOR))
1603         wIndex = NO_SELECTED_ITEM;
1604
1605     if (lppop->FocusedItem == wIndex) return;
1606     if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1607     else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1608
1609     SelectObject( hdc, hMenuFont);
1610
1611       /* Clear previous highlighted item */
1612     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
1613     {
1614         lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1615         MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1616                           lppop->Height, !(lppop->wFlags & MF_POPUP),
1617                           ODA_SELECT );
1618     }
1619
1620       /* Highlight new item (if any) */
1621     lppop->FocusedItem = wIndex;
1622     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
1623     {
1624         lppop->items[lppop->FocusedItem].fState |= MF_HILITE;
1625         MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc, &lppop->items[lppop->FocusedItem],
1626                            lppop->Height, !(lppop->wFlags & MF_POPUP),
1627                            ODA_SELECT );
1628         if (sendMenuSelect)
1629         {
1630             MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1631             SendMessageA( hwndOwner, WM_MENUSELECT, 
1632                          MAKELONG(ip->wID,ip->fType | (ip->fState | MF_MOUSESELECT)), hmenu);
1633         }
1634     }
1635     else if (sendMenuSelect) {
1636         SendMessageA( hwndOwner, WM_MENUSELECT, 
1637                      MAKELONG( hmenu, lppop->wFlags | MF_MOUSESELECT), hmenu ); 
1638     }
1639     ReleaseDC( lppop->hWnd, hdc );
1640 }
1641
1642
1643 /***********************************************************************
1644  *           MENU_MoveSelection
1645  *
1646  * Moves currently selected item according to the offset parameter.
1647  * If there is no selection then it should select the last item if
1648  * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1649  */
1650 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1651 {
1652     INT i;
1653     POPUPMENU *menu;
1654
1655     TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1656
1657     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1658     if (!menu->items) return;
1659
1660     if ( menu->FocusedItem != NO_SELECTED_ITEM )
1661     {
1662         if( menu->nItems == 1 ) return; else
1663         for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems 
1664                                             ; i += offset)
1665             if (!(menu->items[i].fType & MF_SEPARATOR))
1666             {
1667                 MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
1668                 return;
1669             }
1670     }
1671
1672     for ( i = (offset > 0) ? 0 : menu->nItems - 1; 
1673                   i >= 0 && i < menu->nItems ; i += offset)
1674         if (!(menu->items[i].fType & MF_SEPARATOR))
1675         {
1676             MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
1677             return;
1678         }
1679 }
1680
1681
1682 /**********************************************************************
1683  *         MENU_SetItemData
1684  *
1685  * Set an item flags, id and text ptr. Called by InsertMenu() and
1686  * ModifyMenu().
1687  */
1688 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1689                                 LPCSTR str )
1690 {
1691     LPSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1692
1693     debug_print_menuitem("MENU_SetItemData from: ", item, "");
1694
1695     if (IS_STRING_ITEM(flags))
1696     {
1697         if (!str || !*str)
1698         {
1699             flags |= MF_SEPARATOR;
1700             item->text = NULL;
1701         }
1702         else
1703         {
1704             LPSTR text;
1705             /* Item beginning with a backspace is a help item */
1706             if (*str == '\b')
1707             {
1708                 flags |= MF_HELP;
1709                 str++;
1710             }
1711             if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1712             item->text = text;
1713         }
1714     }
1715     else if (IS_BITMAP_ITEM(flags))
1716         item->text = (LPSTR)(HBITMAP)LOWORD(str);
1717     else item->text = NULL;
1718
1719     if (flags & MF_OWNERDRAW) 
1720         item->dwItemData = (DWORD)str;
1721     else
1722         item->dwItemData = 0;
1723
1724     if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1725         DestroyMenu( item->hSubMenu );   /* ModifyMenu() spec */
1726
1727     if (flags & MF_POPUP)
1728     {
1729         POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR((UINT16)id);
1730         if (IS_A_MENU(menu)) menu->wFlags |= MF_POPUP;
1731         else
1732         {
1733             item->wID = 0;
1734             item->hSubMenu = 0;
1735             item->fType = 0;
1736             item->fState = 0;
1737             return FALSE;
1738         }
1739     } 
1740
1741     item->wID = id;
1742     if (flags & MF_POPUP)
1743       item->hSubMenu = id;
1744
1745     if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1746       flags |= MF_POPUP; /* keep popup */
1747
1748     item->fType = flags & TYPE_MASK;
1749     item->fState = (flags & STATE_MASK) &
1750         ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1751
1752
1753     /* Don't call SetRectEmpty here! */
1754
1755
1756     if (prevText) HeapFree( SystemHeap, 0, prevText );
1757
1758     debug_print_menuitem("MENU_SetItemData to  : ", item, "");
1759     return TRUE;
1760 }
1761
1762
1763 /**********************************************************************
1764  *         MENU_InsertItem
1765  *
1766  * Insert a new item into a menu.
1767  */
1768 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1769 {
1770     MENUITEM *newItems;
1771     POPUPMENU *menu;
1772
1773     if (!(menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu))) 
1774     {
1775         WARN("%04x not a menu handle\n",
1776                       hMenu );
1777         return NULL;
1778     }
1779
1780     /* Find where to insert new item */
1781
1782     if ((flags & MF_BYPOSITION) &&
1783         ((pos == (UINT)-1) || (pos == menu->nItems)))
1784     {
1785         /* Special case: append to menu */
1786         /* Some programs specify the menu length to do that */
1787         pos = menu->nItems;
1788     }
1789     else
1790     {
1791         if (!MENU_FindItem( &hMenu, &pos, flags )) 
1792         {
1793             WARN("item %x not found\n",
1794                           pos );
1795             return NULL;
1796         }
1797         if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
1798         {
1799             WARN("%04x not a menu handle\n",
1800                          hMenu);
1801             return NULL;
1802         }
1803     }
1804
1805     /* Create new items array */
1806
1807     newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1808     if (!newItems)
1809     {
1810         WARN("allocation failed\n" );
1811         return NULL;
1812     }
1813     if (menu->nItems > 0)
1814     {
1815           /* Copy the old array into the new */
1816         if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1817         if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1818                                         (menu->nItems-pos)*sizeof(MENUITEM) );
1819         HeapFree( SystemHeap, 0, menu->items );
1820     }
1821     menu->items = newItems;
1822     menu->nItems++;
1823     memset( &newItems[pos], 0, sizeof(*newItems) );
1824     return &newItems[pos];
1825 }
1826
1827
1828 /**********************************************************************
1829  *         MENU_ParseResource
1830  *
1831  * Parse a standard menu resource and add items to the menu.
1832  * Return a pointer to the end of the resource.
1833  */
1834 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1835 {
1836     WORD flags, id = 0;
1837     LPCSTR str;
1838
1839     do
1840     {
1841         flags = GET_WORD(res);
1842         res += sizeof(WORD);
1843         if (!(flags & MF_POPUP))
1844         {
1845             id = GET_WORD(res);
1846             res += sizeof(WORD);
1847         }
1848         if (!IS_STRING_ITEM(flags))
1849             ERR("not a string item %04x\n", flags );
1850         str = res;
1851         if (!unicode) res += strlen(str) + 1;
1852         else res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1853         if (flags & MF_POPUP)
1854         {
1855             HMENU hSubMenu = CreatePopupMenu();
1856             if (!hSubMenu) return NULL;
1857             if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1858                 return NULL;
1859             if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1860             else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1861         }
1862         else  /* Not a popup */
1863         {
1864             if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1865             else AppendMenuW( hMenu, flags, id,
1866                                 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1867         }
1868     } while (!(flags & MF_END));
1869     return res;
1870 }
1871
1872
1873 /**********************************************************************
1874  *         MENUEX_ParseResource
1875  *
1876  * Parse an extended menu resource and add items to the menu.
1877  * Return a pointer to the end of the resource.
1878  */
1879 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1880 {
1881     WORD resinfo;
1882     do {
1883         MENUITEMINFOW mii;
1884
1885         mii.cbSize = sizeof(mii);
1886         mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1887         mii.fType = GET_DWORD(res);
1888         res += sizeof(DWORD);
1889         mii.fState = GET_DWORD(res);
1890         res += sizeof(DWORD);
1891         mii.wID = GET_DWORD(res);
1892         res += sizeof(DWORD);
1893         resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte.  */
1894         res += sizeof(WORD);
1895         /* Align the text on a word boundary.  */
1896         res += (~((int)res - 1)) & 1;
1897         mii.dwTypeData = (LPWSTR) res;
1898         res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
1899         /* Align the following fields on a dword boundary.  */
1900         res += (~((int)res - 1)) & 3;
1901
1902         /* FIXME: This is inefficient and cannot be optimised away by gcc.  */
1903         {
1904             LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
1905                                            0, mii.dwTypeData);
1906             TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1907                          mii.fType, mii.fState, mii.wID, resinfo, newstr);
1908             HeapFree( GetProcessHeap(), 0, newstr );
1909         }
1910
1911         if (resinfo & 1) {      /* Pop-up? */
1912             /* DWORD helpid = GET_DWORD(res); FIXME: use this.  */
1913             res += sizeof(DWORD);
1914             mii.hSubMenu = CreatePopupMenu();
1915             if (!mii.hSubMenu)
1916                 return NULL;
1917             if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
1918                 DestroyMenu(mii.hSubMenu);
1919                 return NULL;
1920         }
1921             mii.fMask |= MIIM_SUBMENU;
1922             mii.fType |= MF_POPUP;
1923         }
1924         InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
1925     } while (!(resinfo & MF_END));
1926     return res;
1927 }
1928
1929
1930 /***********************************************************************
1931  *           MENU_GetSubPopup
1932  *
1933  * Return the handle of the selected sub-popup menu (if any).
1934  */
1935 static HMENU MENU_GetSubPopup( HMENU hmenu )
1936 {
1937     POPUPMENU *menu;
1938     MENUITEM *item;
1939
1940     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1941
1942     if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
1943
1944     item = &menu->items[menu->FocusedItem];
1945     if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
1946         return item->hSubMenu;
1947     return 0;
1948 }
1949
1950
1951 /***********************************************************************
1952  *           MENU_HideSubPopups
1953  *
1954  * Hide the sub-popup menus of this menu.
1955  */
1956 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
1957                                 BOOL sendMenuSelect )
1958 {
1959     POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR( hmenu );;
1960
1961     TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
1962
1963     if (menu && uSubPWndLevel)
1964     {
1965         HMENU hsubmenu;
1966         POPUPMENU *submenu;
1967         MENUITEM *item;
1968
1969         if (menu->FocusedItem != NO_SELECTED_ITEM)
1970         {
1971             item = &menu->items[menu->FocusedItem];
1972             if (!(item->fType & MF_POPUP) ||
1973                 !(item->fState & MF_MOUSESELECT)) return;
1974             item->fState &= ~MF_MOUSESELECT;
1975             hsubmenu = item->hSubMenu;
1976         } else return;
1977
1978         submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
1979         MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
1980         MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect );
1981
1982         if (submenu->hWnd == MENU_GetTopPopupWnd()->hwndSelf )
1983         {
1984             ShowWindow( submenu->hWnd, SW_HIDE );
1985             uSubPWndLevel = 0;
1986         }
1987         else
1988         {
1989             DestroyWindow( submenu->hWnd );
1990             submenu->hWnd = 0;
1991         }
1992         MENU_ReleaseTopPopupWnd();
1993     }
1994 }
1995
1996
1997 /***********************************************************************
1998  *           MENU_ShowSubPopup
1999  *
2000  * Display the sub-menu of the selected item of this menu.
2001  * Return the handle of the submenu, or hmenu if no submenu to display.
2002  */
2003 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2004                                   BOOL selectFirst )
2005 {
2006     RECT rect;
2007     POPUPMENU *menu;
2008     MENUITEM *item;
2009     WND *wndPtr;
2010     HDC hdc;
2011
2012     TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2013
2014     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
2015
2016     if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
2017         (menu->FocusedItem == NO_SELECTED_ITEM))
2018     {
2019         WIN_ReleaseWndPtr(wndPtr);
2020         return hmenu;
2021     }
2022
2023     item = &menu->items[menu->FocusedItem];
2024     if (!(item->fType & MF_POPUP) ||
2025         (item->fState & (MF_GRAYED | MF_DISABLED)))
2026     {
2027         WIN_ReleaseWndPtr(wndPtr);
2028         return hmenu;
2029     }
2030
2031     /* message must be send before using item,
2032        because nearly everything may by changed by the application ! */
2033
2034     SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2035                    MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2036
2037     item = &menu->items[menu->FocusedItem];
2038     rect = item->rect;
2039
2040     /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2041     if (!(item->fState & MF_HILITE)) 
2042     {
2043         if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2044         else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2045
2046         SelectObject( hdc, hMenuFont);
2047
2048         item->fState |= MF_HILITE;
2049         MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE ); 
2050         ReleaseDC( menu->hWnd, hdc );
2051     }
2052     if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2053       item->rect = rect;
2054
2055     item->fState |= MF_MOUSESELECT;
2056
2057     if (IS_SYSTEM_MENU(menu))
2058     {
2059         MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, GetClassLongA(wndPtr->hwndSelf, GCL_STYLE));
2060
2061         NC_GetSysPopupPos( wndPtr, &rect );
2062         rect.top = rect.bottom;
2063         rect.right = GetSystemMetrics(SM_CXSIZE);
2064         rect.bottom = GetSystemMetrics(SM_CYSIZE);
2065     }
2066     else
2067     {
2068         if (menu->wFlags & MF_POPUP)
2069         {
2070             rect.left = wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width;
2071             rect.top = wndPtr->rectWindow.top + item->rect.top;
2072             rect.right = item->rect.left - item->rect.right + 2*arrow_bitmap_width;
2073             rect.bottom = item->rect.top - item->rect.bottom;
2074         }
2075         else
2076         {
2077             rect.left = wndPtr->rectWindow.left + item->rect.left;
2078             rect.top = wndPtr->rectWindow.top + item->rect.bottom;
2079             rect.right = item->rect.right - item->rect.left;
2080             rect.bottom = item->rect.bottom - item->rect.top;
2081         }
2082     }
2083
2084     MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2085                     rect.left, rect.top, rect.right, rect.bottom );
2086     if (selectFirst)
2087         MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2088     WIN_ReleaseWndPtr(wndPtr);
2089     return item->hSubMenu;
2090 }
2091
2092 /***********************************************************************
2093  *           MENU_PtMenu
2094  *
2095  * Walks menu chain trying to find a menu pt maps to.
2096  */
2097 static HMENU MENU_PtMenu( HMENU hMenu, POINT16 pt )
2098 {
2099    POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
2100    register UINT ht = menu->FocusedItem;
2101
2102    /* try subpopup first (if any) */
2103     ht = (ht != NO_SELECTED_ITEM &&
2104           (menu->items[ht].fType & MF_POPUP) &&
2105           (menu->items[ht].fState & MF_MOUSESELECT))
2106         ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
2107
2108    if( !ht )    /* check the current window (avoiding WM_HITTEST) */
2109    {
2110         ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt );
2111         if( menu->wFlags & MF_POPUP )
2112             ht =  (ht != (UINT)HTNOWHERE && 
2113                    ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
2114         else
2115         {
2116             WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
2117
2118             ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu)
2119                  : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0;
2120             WIN_ReleaseWndPtr(wndPtr);
2121         }
2122    }
2123    return (HMENU)ht;
2124 }
2125
2126 /***********************************************************************
2127  *           MENU_ExecFocusedItem
2128  *
2129  * Execute a menu item (for instance when user pressed Enter).
2130  * Return the wID of the executed item. Otherwise, zero indicating
2131  * that no menu item wase executed;
2132  * Have to receive the flags for the TrackPopupMenu options to avoid
2133  * sending unwanted message.
2134  *
2135  */
2136 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2137 {
2138     MENUITEM *item;
2139     POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
2140
2141     TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2142
2143     if (!menu || !menu->nItems || 
2144         (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2145
2146     item = &menu->items[menu->FocusedItem];
2147
2148     TRACE("%08x %08x %08x\n",
2149                  hMenu, item->wID, item->hSubMenu);
2150
2151     if (!(item->fType & MF_POPUP))
2152     {
2153         if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
2154         {
2155             /* If TPM_RETURNCMD is set you return the id, but 
2156                do not send a message to the owner */       
2157             if(!(wFlags & TPM_RETURNCMD))
2158             {
2159                 if( menu->wFlags & MF_SYSMENU )
2160                     PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2161                                   MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2162                 else
2163                     PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2164             }
2165             return item->wID;
2166         }
2167     }
2168     else
2169         pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hMenu, TRUE );
2170
2171     return 0;
2172 }
2173
2174 /***********************************************************************
2175  *           MENU_SwitchTracking
2176  *
2177  * Helper function for menu navigation routines.
2178  */
2179 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2180 {
2181     POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
2182     POPUPMENU *topmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
2183
2184     TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2185
2186     if( pmt->hTopMenu != hPtMenu &&
2187         !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2188     {
2189         /* both are top level menus (system and menu-bar) */
2190
2191         MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2192         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
2193         pmt->hTopMenu = hPtMenu;
2194     }
2195     else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2196     MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE );
2197 }
2198
2199
2200 /***********************************************************************
2201  *           MENU_ButtonDown
2202  *
2203  * Return TRUE if we can go on with menu tracking.
2204  */
2205 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu )
2206 {
2207     TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2208
2209     if (hPtMenu)
2210     {
2211         UINT id = 0;
2212         POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
2213         MENUITEM *item;
2214
2215         if( IS_SYSTEM_MENU(ptmenu) )
2216             item = ptmenu->items;
2217         else
2218             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2219
2220         if( item )
2221         {
2222             if( ptmenu->FocusedItem == id )
2223             {
2224                 /* nothing to do with already selected non-popup */
2225                 if( !(item->fType & MF_POPUP) ) return TRUE;
2226
2227                 if( item->fState & MF_MOUSESELECT )
2228                 {
2229                     if( ptmenu->wFlags & MF_POPUP )
2230                     {
2231                         /* hide selected subpopup */
2232
2233                         MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, TRUE );
2234                         pmt->hCurrentMenu = hPtMenu;
2235                         return TRUE;
2236                     }
2237                     return FALSE; /* shouldn't get here */
2238                 } 
2239             }
2240             else MENU_SwitchTracking( pmt, hPtMenu, id );
2241
2242             /* try to display a subpopup */
2243
2244             pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
2245             return TRUE;
2246         } 
2247         else WARN("\tunable to find clicked item!\n");
2248     }
2249     return FALSE;
2250 }
2251
2252 /***********************************************************************
2253  *           MENU_ButtonUp
2254  *
2255  * Return the value of MENU_ExecFocusedItem if
2256  * the selected item was not a popup. Else open the popup.
2257  * A zero return value indicates that we go on with menu tracking.
2258  *
2259  */
2260 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2261 {
2262     TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2263
2264     if (hPtMenu)
2265     {
2266         UINT id = 0;
2267         POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
2268         MENUITEM *item;
2269
2270         if( IS_SYSTEM_MENU(ptmenu) )
2271             item = ptmenu->items;
2272         else
2273             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2274
2275         if( item && (ptmenu->FocusedItem == id ))
2276         {
2277             if( !(item->fType & MF_POPUP) )
2278                 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2279             hPtMenu = item->hSubMenu;
2280             if( hPtMenu == pmt->hCurrentMenu )
2281             {
2282                 /* Select first item of sub-popup */    
2283
2284                 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, NO_SELECTED_ITEM, FALSE );
2285                 MENU_MoveSelection( pmt->hOwnerWnd, hPtMenu, ITEM_NEXT );
2286             }
2287         }
2288     }
2289     return 0;
2290 }
2291
2292
2293 /***********************************************************************
2294  *           MENU_MouseMove
2295  *
2296  * Return TRUE if we can go on with menu tracking.
2297  */
2298 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu )
2299 {
2300     UINT id = NO_SELECTED_ITEM;
2301     POPUPMENU *ptmenu = NULL;
2302
2303     if( hPtMenu )
2304     {
2305         ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
2306         if( IS_SYSTEM_MENU(ptmenu) )
2307             id = 0;
2308         else
2309             MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2310     } 
2311
2312     if( id == NO_SELECTED_ITEM )
2313     {
2314         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, 
2315                          NO_SELECTED_ITEM, TRUE );
2316     }
2317     else if( ptmenu->FocusedItem != id )
2318     {
2319             MENU_SwitchTracking( pmt, hPtMenu, id );
2320             pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
2321     }
2322     return TRUE;
2323 }
2324
2325
2326 /***********************************************************************
2327  *           MENU_DoNextMenu
2328  *
2329  * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2330  */
2331 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2332 {
2333     POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
2334
2335     if( (vk == VK_LEFT &&  menu->FocusedItem == 0 ) ||
2336         (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2337     {
2338         WND*    wndPtr;
2339         HMENU hNewMenu;
2340         HWND  hNewWnd;
2341         UINT  id = 0;
2342         LRESULT l = SendMessageA( pmt->hOwnerWnd, WM_NEXTMENU, vk, 
2343                 (IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
2344
2345         TRACE("%04x [%04x] -> %04x [%04x]\n",
2346                      (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
2347
2348         if( l == 0 )
2349         {
2350             wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
2351
2352             hNewWnd = pmt->hOwnerWnd;
2353             if( IS_SYSTEM_MENU(menu) )
2354             {
2355                 /* switch to the menu bar */
2356
2357                 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu ) 
2358                 {
2359                     WIN_ReleaseWndPtr(wndPtr);
2360                     return FALSE;
2361                 }
2362
2363                 hNewMenu = wndPtr->wIDmenu;
2364                 if( vk == VK_LEFT )
2365                 {
2366                     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hNewMenu );
2367                     id = menu->nItems - 1;
2368                 }
2369             }
2370             else if( wndPtr->dwStyle & WS_SYSMENU ) 
2371             {
2372                 /* switch to the system menu */
2373                 hNewMenu = wndPtr->hSysMenu; 
2374             }
2375             else
2376             {
2377                 WIN_ReleaseWndPtr(wndPtr);
2378                 return FALSE;
2379         }
2380             WIN_ReleaseWndPtr(wndPtr);
2381         }
2382         else    /* application returned a new menu to switch to */
2383         {
2384             hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
2385
2386             if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2387             {
2388                 wndPtr = WIN_FindWndPtr(hNewWnd);
2389
2390                 if( wndPtr->dwStyle & WS_SYSMENU &&
2391                     GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
2392                 {
2393                     /* get the real system menu */
2394                     hNewMenu =  wndPtr->hSysMenu;
2395                 }
2396                 else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
2397                 {
2398                     /* FIXME: Not sure what to do here, perhaps,
2399                      * try to track hNewMenu as a popup? */
2400
2401                     TRACE(" -- got confused.\n");
2402                     WIN_ReleaseWndPtr(wndPtr);
2403                     return FALSE;
2404                 }
2405                 WIN_ReleaseWndPtr(wndPtr);
2406             }
2407             else return FALSE;
2408         }
2409
2410         if( hNewMenu != pmt->hTopMenu )
2411         {
2412             MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
2413             if( pmt->hCurrentMenu != pmt->hTopMenu ) 
2414                 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2415         }
2416
2417         if( hNewWnd != pmt->hOwnerWnd )
2418         {
2419             ReleaseCapture(); 
2420             pmt->hOwnerWnd = hNewWnd;
2421             EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2422         }
2423
2424         pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2425         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE ); 
2426
2427         return TRUE;
2428     }
2429     return FALSE;
2430 }
2431
2432 /***********************************************************************
2433  *           MENU_SuspendPopup
2434  *
2435  * The idea is not to show the popup if the next input message is
2436  * going to hide it anyway.
2437  */
2438 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2439 {
2440     MSG msg;
2441
2442     msg.hwnd = pmt->hOwnerWnd;
2443
2444     PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2445     pmt->trackFlags |= TF_SKIPREMOVE;
2446
2447     switch( uMsg )
2448     {
2449         case WM_KEYDOWN:
2450              PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2451              if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2452              {
2453                  PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2454                  PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2455                  if( msg.message == WM_KEYDOWN &&
2456                     (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2457                  {
2458                      pmt->trackFlags |= TF_SUSPENDPOPUP;
2459                      return TRUE;
2460                  }
2461              }
2462              break;
2463     }
2464
2465     /* failures go through this */
2466     pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2467     return FALSE;
2468 }
2469
2470 /***********************************************************************
2471  *           MENU_KeyLeft
2472  *
2473  * Handle a VK_LEFT key event in a menu. 
2474  */
2475 static void MENU_KeyLeft( MTRACKER* pmt )
2476 {
2477     POPUPMENU *menu;
2478     HMENU hmenutmp, hmenuprev;
2479     UINT  prevcol;
2480
2481     hmenuprev = hmenutmp = pmt->hTopMenu;
2482     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenutmp );
2483
2484     /* Try to move 1 column left (if possible) */
2485     if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) != 
2486         NO_SELECTED_ITEM ) {
2487         
2488         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2489                          prevcol, TRUE );
2490         return;
2491     }
2492
2493     /* close topmost popup */
2494     while (hmenutmp != pmt->hCurrentMenu)
2495     {
2496         hmenuprev = hmenutmp;
2497         hmenutmp = MENU_GetSubPopup( hmenuprev );
2498     }
2499
2500     MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2501     pmt->hCurrentMenu = hmenuprev; 
2502
2503     if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2504     {
2505         /* move menu bar selection if no more popups are left */
2506
2507         if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2508              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2509
2510         if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2511         {
2512            /* A sublevel menu was displayed - display the next one
2513             * unless there is another displacement coming up */
2514
2515             if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2516                 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd,
2517                                                 pmt->hTopMenu, TRUE );
2518         }
2519     }
2520 }
2521
2522
2523 /***********************************************************************
2524  *           MENU_KeyRight
2525  *
2526  * Handle a VK_RIGHT key event in a menu.
2527  */
2528 static void MENU_KeyRight( MTRACKER* pmt )
2529 {
2530     HMENU hmenutmp;
2531     POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
2532     UINT  nextcol;
2533
2534     TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2535                   pmt->hCurrentMenu,
2536                   ((POPUPMENU *)USER_HEAP_LIN_ADDR(pmt->hCurrentMenu))->
2537                      items[0].text,
2538                   pmt->hTopMenu, menu->items[0].text );
2539
2540     if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2541     {
2542         /* If already displaying a popup, try to display sub-popup */
2543
2544         hmenutmp = pmt->hCurrentMenu;
2545         pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hmenutmp, TRUE );
2546
2547         /* if subpopup was displayed then we are done */
2548         if (hmenutmp != pmt->hCurrentMenu) return;
2549     }
2550
2551     /* Check to see if there's another column */
2552     if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) != 
2553         NO_SELECTED_ITEM ) {
2554         TRACE("Going to %d.\n", nextcol );
2555         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2556                          nextcol, TRUE );
2557         return;
2558     }
2559
2560     if (!(menu->wFlags & MF_POPUP))     /* menu bar tracking */
2561     {
2562         if( pmt->hCurrentMenu != pmt->hTopMenu )
2563         {
2564             MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2565             hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2566         } else hmenutmp = 0;
2567
2568         /* try to move to the next item */
2569         if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2570              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2571
2572         if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2573             if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2574                 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, 
2575                                                        pmt->hTopMenu, TRUE );
2576     }
2577 }
2578
2579 /***********************************************************************
2580  *           MENU_TrackMenu
2581  *
2582  * Menu tracking code.
2583  */
2584 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2585                               HWND hwnd, const RECT *lprect )
2586 {
2587     MSG msg;
2588     POPUPMENU *menu;
2589     BOOL fRemove;
2590     INT executedMenuId = 0;
2591     MTRACKER mt;
2592     BOOL enterIdleSent = FALSE;
2593
2594     mt.trackFlags = 0;
2595     mt.hCurrentMenu = hmenu;
2596     mt.hTopMenu = hmenu;
2597     mt.hOwnerWnd = hwnd;
2598     mt.pt.x = x;
2599     mt.pt.y = y;
2600
2601     TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2602             hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2603             (lprect) ? lprect->right : 0,  (lprect) ? lprect->bottom : 0);
2604
2605     fEndMenu = FALSE;
2606     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
2607
2608     if (wFlags & TPM_BUTTONDOWN) MENU_ButtonDown( &mt, hmenu );
2609
2610     EVENT_Capture( mt.hOwnerWnd, HTMENU );
2611
2612     while (!fEndMenu)
2613     {
2614         menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
2615         msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2616
2617         /* we have to keep the message in the queue until it's
2618          * clear that menu loop is not over yet. */
2619
2620         if (!MSG_InternalGetMessage( &msg, msg.hwnd, mt.hOwnerWnd,
2621                                      MSGF_MENU, PM_NOREMOVE, !enterIdleSent, &enterIdleSent )) break;
2622
2623         TranslateMessage( &msg );
2624         mt.pt = msg.pt;
2625
2626         if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2627           enterIdleSent=FALSE;
2628
2629         fRemove = FALSE;
2630         if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2631         {
2632             /* Find a menu for this mouse event */
2633             POINT16 pt16;
2634             CONV_POINT32TO16( &msg.pt, &pt16 );
2635             hmenu = MENU_PtMenu( mt.hTopMenu, pt16 );
2636
2637             switch(msg.message)
2638             {
2639                 /* no WM_NC... messages in captured state */
2640
2641                 case WM_RBUTTONDBLCLK:
2642                 case WM_RBUTTONDOWN:
2643                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
2644                     /* fall through */
2645                 case WM_LBUTTONDBLCLK:
2646                 case WM_LBUTTONDOWN:
2647                     fEndMenu |= !MENU_ButtonDown( &mt, hmenu );
2648                     break;
2649                 
2650                 case WM_RBUTTONUP:
2651                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
2652                     /* fall through */
2653                 case WM_LBUTTONUP:
2654                     /* Check if a menu was selected by the mouse */
2655                     if (hmenu)
2656                     {
2657                         executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2658
2659                         /* End the loop if executedMenuId is an item ID */
2660                         /* or if the job was done (executedMenuId = 1). */
2661                         fEndMenu = fRemove = (executedMenuId != 0);
2662                     }
2663                     /* No menu was selected by the mouse */
2664                     /* if the function was called by TrackPopupMenu, continue
2665                        with the menu tracking. If not, stop it */
2666                     else
2667                         fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2668                     
2669                     break;
2670                 
2671                 case WM_MOUSEMOVE:
2672                     /* In win95 winelook, the selected menu item must be changed every time the
2673                        mouse moves. In Win31 winelook, the mouse button has to be held down */
2674                      
2675                     if ( (TWEAK_WineLook > WIN31_LOOK) ||
2676                          ( (msg.wParam & MK_LBUTTON) ||
2677                            ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2678
2679                         fEndMenu |= !MENU_MouseMove( &mt, hmenu );
2680
2681             } /* switch(msg.message) - mouse */
2682         }
2683         else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2684         {
2685             fRemove = TRUE;  /* Keyboard messages are always removed */
2686             switch(msg.message)
2687             {
2688             case WM_KEYDOWN:
2689                 switch(msg.wParam)
2690                 {
2691                 case VK_HOME:
2692                 case VK_END:
2693                     MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, 
2694                                      NO_SELECTED_ITEM, FALSE );
2695                 /* fall through */
2696                 case VK_UP:
2697                     MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, 
2698                                        (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2699                     break;
2700
2701                 case VK_DOWN: /* If on menu bar, pull-down the menu */
2702
2703                     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
2704                     if (!(menu->wFlags & MF_POPUP))
2705                         mt.hCurrentMenu = MENU_ShowSubPopup( mt.hOwnerWnd, mt.hTopMenu, TRUE );
2706                     else      /* otherwise try to move selection */
2707                         MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2708                     break;
2709
2710                 case VK_LEFT:
2711                     MENU_KeyLeft( &mt );
2712                     break;
2713                     
2714                 case VK_RIGHT:
2715                     MENU_KeyRight( &mt );
2716                     break;
2717                     
2718                 case VK_ESCAPE:
2719                     fEndMenu = TRUE;
2720                     break;
2721
2722                 default:
2723                     break;
2724                 }
2725                 break;  /* WM_KEYDOWN */
2726
2727             case WM_SYSKEYDOWN:
2728                 switch(msg.wParam)
2729                 {
2730                 case VK_MENU:
2731                     fEndMenu = TRUE;
2732                     break;
2733                     
2734                 }
2735                 break;  /* WM_SYSKEYDOWN */
2736
2737             case WM_CHAR:
2738                 {
2739                     UINT        pos;
2740
2741                     if (msg.wParam == '\r' || msg.wParam == ' ')
2742                     {
2743                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2744                         fEndMenu = (executedMenuId != 0);
2745
2746                         break;
2747                     }
2748
2749                       /* Hack to avoid control chars. */
2750                       /* We will find a better way real soon... */
2751                     if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2752
2753                     pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu, 
2754                                               LOWORD(msg.wParam), FALSE );
2755                     if (pos == (UINT)-2) fEndMenu = TRUE;
2756                     else if (pos == (UINT)-1) MessageBeep(0);
2757                     else
2758                     {
2759                         MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos, TRUE );
2760                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2761                         fEndMenu = (executedMenuId != 0);
2762                     }
2763                 }                   
2764                 break;
2765             }  /* switch(msg.message) - kbd */
2766         }
2767         else
2768         {
2769             DispatchMessageA( &msg );
2770         }
2771
2772         if (!fEndMenu) fRemove = TRUE;
2773
2774         /* finally remove message from the queue */
2775
2776         if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2777             PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2778         else mt.trackFlags &= ~TF_SKIPREMOVE;
2779     }
2780
2781     ReleaseCapture();
2782
2783     if( IsWindow( mt.hOwnerWnd ) )
2784     {
2785         MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2786
2787         menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hTopMenu );
2788         if (menu && menu->wFlags & MF_POPUP) 
2789         {
2790             ShowWindow( menu->hWnd, SW_HIDE );
2791             uSubPWndLevel = 0;
2792         }
2793         MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE );
2794         SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0), 0xffff );
2795     }
2796
2797     /* returning the id of the selected menu.
2798       The return value is only used by TrackPopupMenu */
2799     return executedMenuId;
2800 }
2801
2802 /***********************************************************************
2803  *           MENU_InitTracking
2804  */
2805 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup)
2806 {
2807
2808     TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
2809
2810     HideCaret(0);
2811     SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2812     SendMessageA( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
2813     SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
2814     return TRUE;
2815 }
2816 /***********************************************************************
2817  *           MENU_ExitTracking
2818  */
2819 static BOOL MENU_ExitTracking(HWND hWnd)
2820 {
2821     TRACE("hwnd=0x%04x\n", hWnd);
2822
2823     SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2824     ShowCaret(0);
2825     return TRUE;
2826 }
2827
2828 /***********************************************************************
2829  *           MENU_TrackMouseMenuBar
2830  *
2831  * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2832  */
2833 void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt )
2834 {
2835     HWND  hWnd = wndPtr->hwndSelf;
2836     HMENU hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
2837
2838     TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr, ht, pt.x, pt.y);
2839
2840     if (IsMenu(hMenu))
2841     {
2842         MENU_InitTracking( hWnd, hMenu, FALSE );
2843         MENU_TrackMenu( hMenu, TPM_ENTERIDLEEX | TPM_BUTTONDOWN | 
2844                         TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, hWnd, NULL );
2845         MENU_ExitTracking(hWnd);
2846     }
2847 }
2848
2849
2850 /***********************************************************************
2851  *           MENU_TrackKbdMenuBar
2852  *
2853  * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2854  */
2855 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
2856 {
2857    UINT uItem = NO_SELECTED_ITEM;
2858    HMENU hTrackMenu; 
2859
2860     /* find window that has a menu */
2861  
2862     while( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwStyle & WS_SYSMENU) )
2863         if( !(wndPtr = wndPtr->parent) ) return;
2864
2865     /* check if we have to track a system menu */
2866           
2867     if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) || 
2868         !wndPtr->wIDmenu || vkey == VK_SPACE )
2869     {
2870         if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
2871         hTrackMenu = wndPtr->hSysMenu;
2872         uItem = 0;
2873         wParam |= HTSYSMENU;    /* prevent item lookup */
2874     }
2875     else
2876         hTrackMenu = wndPtr->wIDmenu;
2877
2878     if (IsMenu( hTrackMenu ))
2879     {
2880         MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu, FALSE );
2881
2882         if( vkey && vkey != VK_SPACE )
2883         {
2884             uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu, 
2885                                         vkey, (wParam & HTSYSMENU) );
2886             if( uItem >= (UINT)(-2) )
2887             {
2888                 if( uItem == (UINT)(-1) ) MessageBeep(0);
2889                 hTrackMenu = 0;
2890             }
2891         }
2892
2893         if( hTrackMenu )
2894         {
2895             MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE );
2896
2897             if( uItem == NO_SELECTED_ITEM )
2898                 MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
2899             else if( vkey )
2900                 PostMessageA( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
2901
2902             MENU_TrackMenu( hTrackMenu, TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON,
2903                             0, 0, wndPtr->hwndSelf, NULL );
2904         }
2905
2906         MENU_ExitTracking (wndPtr->hwndSelf);
2907     }
2908 }
2909
2910
2911 /**********************************************************************
2912  *           TrackPopupMenu16   (USER.416)
2913  */
2914 BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
2915                            INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
2916 {
2917     RECT r;
2918     if (lpRect)
2919          CONV_RECT16TO32( lpRect, &r );
2920     return TrackPopupMenu( hMenu, wFlags, x, y, nReserved, hWnd,
2921                              lpRect ? &r : NULL );
2922 }
2923
2924
2925 /**********************************************************************
2926  *           TrackPopupMenu   (USER32.549)
2927  *
2928  * Like the win32 API, the function return the command ID only if the
2929  * flag TPM_RETURNCMD is on.
2930  *
2931  */
2932 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
2933                            INT nReserved, HWND hWnd, const RECT *lpRect )
2934 {
2935     BOOL ret = FALSE;
2936
2937     MENU_InitTracking(hWnd, hMenu, TRUE);
2938     SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
2939     if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
2940         ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
2941     MENU_ExitTracking(hWnd);
2942
2943     if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
2944         ret = 1;
2945
2946     return ret;
2947 }
2948
2949 /**********************************************************************
2950  *           TrackPopupMenuEx   (USER32.550)
2951  */
2952 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
2953                                 HWND hWnd, LPTPMPARAMS lpTpm )
2954 {
2955     FIXME("not fully implemented\n" );
2956     return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
2957                              lpTpm ? &lpTpm->rcExclude : NULL );
2958 }
2959
2960 /***********************************************************************
2961  *           PopupMenuWndProc
2962  *
2963  * NOTE: Windows has totally different (and undocumented) popup wndproc.
2964  */
2965 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
2966                                  LPARAM lParam )
2967 {    
2968     WND* wndPtr = WIN_FindWndPtr(hwnd);
2969     LRESULT retvalue;
2970
2971     TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
2972     hwnd, message, wParam, lParam);
2973
2974     switch(message)
2975     {
2976     case WM_CREATE:
2977         {
2978             CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
2979             SetWindowLongA( hwnd, 0, (LONG)cs->lpCreateParams );
2980             retvalue = 0;
2981             goto END;
2982         }
2983
2984     case WM_MOUSEACTIVATE:  /* We don't want to be activated */
2985         retvalue = MA_NOACTIVATE;
2986         goto END;
2987
2988     case WM_PAINT:
2989         {
2990             PAINTSTRUCT ps;
2991             BeginPaint( hwnd, &ps );
2992             MENU_DrawPopupMenu( hwnd, ps.hdc,
2993                                 (HMENU)GetWindowLongA( hwnd, 0 ) );
2994             EndPaint( hwnd, &ps );
2995             retvalue = 0;
2996             goto END;
2997         }
2998     case WM_ERASEBKGND:
2999         retvalue = 1;
3000         goto END;
3001
3002     case WM_DESTROY:
3003
3004         /* zero out global pointer in case resident popup window
3005          * was somehow destroyed. */
3006
3007         if(MENU_GetTopPopupWnd() )
3008         {
3009             if( hwnd == pTopPopupWnd->hwndSelf )
3010             {
3011                 ERR("resident popup destroyed!\n");
3012
3013                 MENU_DestroyTopPopupWnd();
3014                 uSubPWndLevel = 0;
3015             }
3016             else
3017                 uSubPWndLevel--;
3018             MENU_ReleaseTopPopupWnd();
3019         }
3020         break;
3021
3022     case WM_SHOWWINDOW:
3023
3024         if( wParam )
3025         {
3026             if( !(*(HMENU*)wndPtr->wExtra) )
3027                 ERR("no menu to display\n");
3028         }
3029         else
3030             *(HMENU*)wndPtr->wExtra = 0;
3031         break;
3032
3033     case MM_SETMENUHANDLE:
3034
3035         *(HMENU*)wndPtr->wExtra = (HMENU)wParam;
3036         break;
3037
3038     case MM_GETMENUHANDLE:
3039
3040         retvalue = *(HMENU*)wndPtr->wExtra;
3041         goto END;
3042
3043     default:
3044         retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
3045         goto END;
3046     }
3047     retvalue = 0;
3048 END:
3049     WIN_ReleaseWndPtr(wndPtr);
3050     return retvalue;
3051 }
3052
3053
3054 /***********************************************************************
3055  *           MENU_GetMenuBarHeight
3056  *
3057  * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3058  */
3059 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3060                               INT orgX, INT orgY )
3061 {
3062     HDC hdc;
3063     RECT rectBar;
3064     WND *wndPtr;
3065     LPPOPUPMENU lppop;
3066     UINT retvalue;
3067
3068     TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3069                  hwnd, menubarWidth, orgX, orgY );
3070     
3071     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
3072         return 0;
3073
3074     if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu)))
3075     {
3076         WIN_ReleaseWndPtr(wndPtr);
3077         return 0;
3078     }
3079
3080     hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3081     SelectObject( hdc, hMenuFont);       
3082     SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3083     MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );    
3084     ReleaseDC( hwnd, hdc );
3085     retvalue = lppop->Height;
3086     WIN_ReleaseWndPtr(wndPtr);
3087     return retvalue;
3088 }
3089
3090
3091 /*******************************************************************
3092  *         ChangeMenu16    (USER.153)
3093  */
3094 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3095                             UINT16 id, UINT16 flags )
3096 {
3097     TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3098                   hMenu, pos, (DWORD)data, id, flags );
3099     if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3100                                                 id, data );
3101
3102     /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3103     /* for MF_DELETE. We should check the parameters for all others */
3104     /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3105
3106     if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3107     if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3108                                                id, data );
3109     if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
3110                                               flags & MF_BYPOSITION ? pos : id,
3111                                               flags & ~MF_REMOVE );
3112     /* Default: MF_INSERT */
3113     return InsertMenu16( hMenu, pos, flags, id, data );
3114 }
3115
3116
3117 /*******************************************************************
3118  *         ChangeMenu32A    (USER32.23)
3119  */
3120 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3121                              UINT id, UINT flags )
3122 {
3123     TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3124                   hMenu, pos, (DWORD)data, id, flags );
3125     if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3126                                                  id, data );
3127     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3128     if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3129                                                 id, data );
3130     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3131                                               flags & MF_BYPOSITION ? pos : id,
3132                                               flags & ~MF_REMOVE );
3133     /* Default: MF_INSERT */
3134     return InsertMenuA( hMenu, pos, flags, id, data );
3135 }
3136
3137
3138 /*******************************************************************
3139  *         ChangeMenu32W    (USER32.24)
3140  */
3141 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3142                              UINT id, UINT flags )
3143 {
3144     TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3145                   hMenu, pos, (DWORD)data, id, flags );
3146     if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3147                                                  id, data );
3148     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3149     if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3150                                                 id, data );
3151     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3152                                               flags & MF_BYPOSITION ? pos : id,
3153                                               flags & ~MF_REMOVE );
3154     /* Default: MF_INSERT */
3155     return InsertMenuW( hMenu, pos, flags, id, data );
3156 }
3157
3158
3159 /*******************************************************************
3160  *         CheckMenuItem16    (USER.154)
3161  */
3162 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
3163 {
3164     return (BOOL16)CheckMenuItem( hMenu, id, flags );
3165 }
3166
3167
3168 /*******************************************************************
3169  *         CheckMenuItem    (USER32.46)
3170  */
3171 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3172 {
3173     MENUITEM *item;
3174     DWORD ret;
3175
3176     TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3177     if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3178     ret = item->fState & MF_CHECKED;
3179     if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3180     else item->fState &= ~MF_CHECKED;
3181     return ret;
3182 }
3183
3184
3185 /**********************************************************************
3186  *         EnableMenuItem16    (USER.155)
3187  */
3188 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3189 {
3190     return EnableMenuItem( hMenu, wItemID, wFlags );
3191 }
3192
3193
3194 /**********************************************************************
3195  *         EnableMenuItem32    (USER32.170)
3196  */
3197 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3198 {
3199     UINT    oldflags;
3200     MENUITEM *item;
3201     POPUPMENU *menu;
3202
3203     TRACE("(%04x, %04X, %04X) !\n", 
3204                  hMenu, wItemID, wFlags);
3205
3206     /* Get the Popupmenu to access the owner menu */
3207     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu))) 
3208         return (UINT)-1;
3209
3210     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3211         return (UINT)-1;
3212
3213     oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3214     item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3215
3216     /* In win95 if the close item in the system menu change update the close button */
3217     if (TWEAK_WineLook == WIN95_LOOK)    
3218         if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3219         {
3220             if (menu->hSysMenuOwner != 0)
3221             {
3222                 POPUPMENU* parentMenu;
3223
3224                 /* Get the parent menu to access*/
3225                 if (!(parentMenu = (POPUPMENU *) USER_HEAP_LIN_ADDR(menu->hSysMenuOwner))) 
3226                     return (UINT)-1;
3227
3228                 /* Refresh the frame to reflect the change*/
3229                 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3230                              SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3231             }
3232         }
3233            
3234     return oldflags;
3235 }
3236
3237
3238 /*******************************************************************
3239  *         GetMenuString16    (USER.161)
3240  */
3241 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3242                               LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
3243 {
3244     return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
3245 }
3246
3247
3248 /*******************************************************************
3249  *         GetMenuString32A    (USER32.268)
3250  */
3251 INT WINAPI GetMenuStringA( HMENU hMenu, UINT wItemID,
3252                                LPSTR str, INT nMaxSiz, UINT wFlags )
3253 {
3254     MENUITEM *item;
3255
3256     TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3257                  hMenu, wItemID, str, nMaxSiz, wFlags );
3258     if (!str || !nMaxSiz) return 0;
3259     str[0] = '\0';
3260     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3261     if (!IS_STRING_ITEM(item->fType)) return 0;
3262     lstrcpynA( str, item->text, nMaxSiz );
3263     TRACE("returning '%s'\n", str );
3264     return strlen(str);
3265 }
3266
3267
3268 /*******************************************************************
3269  *         GetMenuString32W    (USER32.269)
3270  */
3271 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3272                                LPWSTR str, INT nMaxSiz, UINT wFlags )
3273 {
3274     MENUITEM *item;
3275
3276     TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3277                  hMenu, wItemID, str, nMaxSiz, wFlags );
3278     if (!str || !nMaxSiz) return 0;
3279     str[0] = '\0';
3280     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3281     if (!IS_STRING_ITEM(item->fType)) return 0;
3282     lstrcpynAtoW( str, item->text, nMaxSiz );
3283     return lstrlenW(str);
3284 }
3285
3286
3287 /**********************************************************************
3288  *         HiliteMenuItem16    (USER.162)
3289  */
3290 BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
3291                                 UINT16 wHilite )
3292 {
3293     return HiliteMenuItem( hWnd, hMenu, wItemID, wHilite );
3294 }
3295
3296
3297 /**********************************************************************
3298  *         HiliteMenuItem32    (USER32.318)
3299  */
3300 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3301                                 UINT wHilite )
3302 {
3303     LPPOPUPMENU menu;
3304     TRACE("(%04x, %04x, %04x, %04x);\n", 
3305                  hWnd, hMenu, wItemID, wHilite);
3306     if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3307     if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
3308     if (menu->FocusedItem == wItemID) return TRUE;
3309     MENU_HideSubPopups( hWnd, hMenu, FALSE );
3310     MENU_SelectItem( hWnd, hMenu, wItemID, TRUE );
3311     return TRUE;
3312 }
3313
3314
3315 /**********************************************************************
3316  *         GetMenuState16    (USER.250)
3317  */
3318 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3319 {
3320     return GetMenuState( hMenu, wItemID, wFlags );
3321 }
3322
3323
3324 /**********************************************************************
3325  *         GetMenuState    (USER32.267)
3326  */
3327 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3328 {
3329     MENUITEM *item;
3330     TRACE("(menu=%04x, id=%04x, flags=%04x);\n", 
3331                  hMenu, wItemID, wFlags);
3332     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3333     debug_print_menuitem ("  item: ", item, "");
3334     if (item->fType & MF_POPUP)
3335     {
3336         POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( item->hSubMenu );
3337         if (!menu) return -1;
3338         else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3339     }
3340     else
3341     {
3342         /* We used to (from way back then) mask the result to 0xff.  */
3343         /* I don't know why and it seems wrong as the documented */
3344         /* return flag MF_SEPARATOR is outside that mask.  */
3345         return (item->fType | item->fState);
3346     }
3347 }
3348
3349
3350 /**********************************************************************
3351  *         GetMenuItemCount16    (USER.263)
3352  */
3353 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3354 {
3355     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3356     if (!IS_A_MENU(menu)) return -1;
3357     TRACE("(%04x) returning %d\n", 
3358                   hMenu, menu->nItems );
3359     return menu->nItems;
3360 }
3361
3362
3363 /**********************************************************************
3364  *         GetMenuItemCount32    (USER32.262)
3365  */
3366 INT WINAPI GetMenuItemCount( HMENU hMenu )
3367 {
3368     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3369     if (!IS_A_MENU(menu)) return -1;
3370     TRACE("(%04x) returning %d\n", 
3371                   hMenu, menu->nItems );
3372     return menu->nItems;
3373 }
3374
3375 /**********************************************************************
3376  *         GetMenuItemID16    (USER.264)
3377  */
3378 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3379 {
3380     return (UINT16) GetMenuItemID (hMenu, nPos);
3381 }
3382
3383 /**********************************************************************
3384  *         GetMenuItemID32    (USER32.263)
3385  */
3386 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3387 {
3388     MENUITEM * lpmi;
3389
3390     if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3391     if (lpmi->fType & MF_POPUP) return -1;
3392     return lpmi->wID;
3393
3394 }
3395
3396 /*******************************************************************
3397  *         InsertMenu16    (USER.410)
3398  */
3399 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3400                             UINT16 id, SEGPTR data )
3401 {
3402     UINT pos32 = (UINT)pos;
3403     if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3404     if (IS_STRING_ITEM(flags) && data)
3405         return InsertMenuA( hMenu, pos32, flags, id,
3406                               (LPSTR)PTR_SEG_TO_LIN(data) );
3407     return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3408 }
3409
3410
3411 /*******************************************************************
3412  *         InsertMenu32A    (USER32.322)
3413  */
3414 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3415                              UINT id, LPCSTR str )
3416 {
3417     MENUITEM *item;
3418
3419     if (IS_STRING_ITEM(flags) && str)
3420         TRACE("hMenu %04x, pos %d, flags %08x, "
3421                       "id %04x, str '%s'\n",
3422                       hMenu, pos, flags, id, str );
3423     else TRACE("hMenu %04x, pos %d, flags %08x, "
3424                        "id %04x, str %08lx (not a string)\n",
3425                        hMenu, pos, flags, id, (DWORD)str );
3426
3427     if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3428
3429     if (!(MENU_SetItemData( item, flags, id, str )))
3430     {
3431         RemoveMenu( hMenu, pos, flags );
3432         return FALSE;
3433     }
3434
3435     if (flags & MF_POPUP)  /* Set the MF_POPUP flag on the popup-menu */
3436         ((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU16)id))->wFlags |= MF_POPUP;
3437
3438     item->hCheckBit = item->hUnCheckBit = 0;
3439     return TRUE;
3440 }
3441
3442
3443 /*******************************************************************
3444  *         InsertMenu32W    (USER32.325)
3445  */
3446 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3447                              UINT id, LPCWSTR str )
3448 {
3449     BOOL ret;
3450
3451     if (IS_STRING_ITEM(flags) && str)
3452     {
3453         LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3454         ret = InsertMenuA( hMenu, pos, flags, id, newstr );
3455         HeapFree( GetProcessHeap(), 0, newstr );
3456         return ret;
3457     }
3458     else return InsertMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3459 }
3460
3461
3462 /*******************************************************************
3463  *         AppendMenu16    (USER.411)
3464  */
3465 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3466 {
3467     return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3468 }
3469
3470
3471 /*******************************************************************
3472  *         AppendMenu32A    (USER32.5)
3473  */
3474 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3475                              UINT id, LPCSTR data )
3476 {
3477     return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3478 }
3479
3480
3481 /*******************************************************************
3482  *         AppendMenu32W    (USER32.6)
3483  */
3484 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3485                              UINT id, LPCWSTR data )
3486 {
3487     return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3488 }
3489
3490
3491 /**********************************************************************
3492  *         RemoveMenu16    (USER.412)
3493  */
3494 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3495 {
3496     return RemoveMenu( hMenu, nPos, wFlags );
3497 }
3498
3499
3500 /**********************************************************************
3501  *         RemoveMenu    (USER32.441)
3502  */
3503 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3504 {
3505     LPPOPUPMENU menu;
3506     MENUITEM *item;
3507
3508     TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3509     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3510     if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
3511     
3512       /* Remove item */
3513
3514     MENU_FreeItemData( item );
3515
3516     if (--menu->nItems == 0)
3517     {
3518         HeapFree( SystemHeap, 0, menu->items );
3519         menu->items = NULL;
3520     }
3521     else
3522     {
3523         while(nPos < menu->nItems)
3524         {
3525             *item = *(item+1);
3526             item++;
3527             nPos++;
3528         }
3529         menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
3530                                    menu->nItems * sizeof(MENUITEM) );
3531     }
3532     return TRUE;
3533 }
3534
3535
3536 /**********************************************************************
3537  *         DeleteMenu16    (USER.413)
3538  */
3539 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3540 {
3541     return DeleteMenu( hMenu, nPos, wFlags );
3542 }
3543
3544
3545 /**********************************************************************
3546  *         DeleteMenu32    (USER32.129)
3547  */
3548 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3549 {
3550     MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3551     if (!item) return FALSE;
3552     if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3553       /* nPos is now the position of the item */
3554     RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3555     return TRUE;
3556 }
3557
3558
3559 /*******************************************************************
3560  *         ModifyMenu16    (USER.414)
3561  */
3562 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3563                             UINT16 id, SEGPTR data )
3564 {
3565     if (IS_STRING_ITEM(flags))
3566         return ModifyMenuA( hMenu, pos, flags, id,
3567                               (LPSTR)PTR_SEG_TO_LIN(data) );
3568     return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3569 }
3570
3571
3572 /*******************************************************************
3573  *         ModifyMenu32A    (USER32.397)
3574  */
3575 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3576                              UINT id, LPCSTR str )
3577 {
3578     MENUITEM *item;
3579
3580     if (IS_STRING_ITEM(flags))
3581     {
3582         TRACE("%04x %d %04x %04x '%s'\n",
3583                       hMenu, pos, flags, id, str ? str : "#NULL#" );
3584         if (!str) return FALSE;
3585     }
3586     else
3587     {
3588         TRACE("%04x %d %04x %04x %08lx\n",
3589                       hMenu, pos, flags, id, (DWORD)str );
3590     }
3591
3592     if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3593     return MENU_SetItemData( item, flags, id, str );
3594 }
3595
3596
3597 /*******************************************************************
3598  *         ModifyMenu32W    (USER32.398)
3599  */
3600 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3601                              UINT id, LPCWSTR str )
3602 {
3603     BOOL ret;
3604
3605     if (IS_STRING_ITEM(flags) && str)
3606     {
3607         LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3608         ret = ModifyMenuA( hMenu, pos, flags, id, newstr );
3609         HeapFree( GetProcessHeap(), 0, newstr );
3610         return ret;
3611     }
3612     else return ModifyMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3613 }
3614
3615
3616 /**********************************************************************
3617  *         CreatePopupMenu16    (USER.415)
3618  */
3619 HMENU16 WINAPI CreatePopupMenu16(void)
3620 {
3621     return CreatePopupMenu();
3622 }
3623
3624
3625 /**********************************************************************
3626  *         CreatePopupMenu32    (USER32.82)
3627  */
3628 HMENU WINAPI CreatePopupMenu(void)
3629 {
3630     HMENU hmenu;
3631     POPUPMENU *menu;
3632
3633     if (!(hmenu = CreateMenu())) return 0;
3634     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
3635     menu->wFlags |= MF_POPUP;
3636     return hmenu;
3637 }
3638
3639
3640 /**********************************************************************
3641  *         GetMenuCheckMarkDimensions    (USER.417) (USER32.258)
3642  */
3643 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3644 {
3645     return MAKELONG( check_bitmap_width, check_bitmap_height );
3646 }
3647
3648
3649 /**********************************************************************
3650  *         SetMenuItemBitmaps16    (USER.418)
3651  */
3652 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3653                                     HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3654 {
3655     return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3656 }
3657
3658
3659 /**********************************************************************
3660  *         SetMenuItemBitmaps32    (USER32.490)
3661  */
3662 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3663                                     HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3664 {
3665     MENUITEM *item;
3666     TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3667                  hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3668     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3669
3670     if (!hNewCheck && !hNewUnCheck)
3671     {
3672         item->fState &= ~MF_USECHECKBITMAPS;
3673     }
3674     else  /* Install new bitmaps */
3675     {
3676         item->hCheckBit = hNewCheck;
3677         item->hUnCheckBit = hNewUnCheck;
3678         item->fState |= MF_USECHECKBITMAPS;
3679     }
3680     return TRUE;
3681 }
3682
3683
3684 /**********************************************************************
3685  *         CreateMenu16    (USER.151)
3686  */
3687 HMENU16 WINAPI CreateMenu16(void)
3688 {
3689     return CreateMenu();
3690 }
3691
3692
3693 /**********************************************************************
3694  *         CreateMenu    (USER32.81)
3695  */
3696 HMENU WINAPI CreateMenu(void)
3697 {
3698     HMENU hMenu;
3699     LPPOPUPMENU menu;
3700     if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3701     menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3702
3703     ZeroMemory(menu, sizeof(POPUPMENU));
3704     menu->wMagic = MENU_MAGIC;
3705     menu->FocusedItem = NO_SELECTED_ITEM;
3706
3707     TRACE("return %04x\n", hMenu );
3708
3709     return hMenu;
3710 }
3711
3712
3713 /**********************************************************************
3714  *         DestroyMenu16    (USER.152)
3715  */
3716 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3717 {
3718     return DestroyMenu( hMenu );
3719 }
3720
3721
3722 /**********************************************************************
3723  *         DestroyMenu32    (USER32.134)
3724  */
3725 BOOL WINAPI DestroyMenu( HMENU hMenu )
3726 {
3727     TRACE("(%04x)\n", hMenu);
3728
3729     /* Silently ignore attempts to destroy default system popup */
3730
3731     if (hMenu && hMenu != MENU_DefSysPopup)
3732     {
3733         LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3734         WND *pTPWnd = MENU_GetTopPopupWnd();
3735
3736         if( pTPWnd && (hMenu == *(HMENU*)pTPWnd->wExtra) )
3737           *(UINT*)pTPWnd->wExtra = 0;
3738
3739         if (IS_A_MENU( lppop ))
3740         {
3741             lppop->wMagic = 0;  /* Mark it as destroyed */
3742
3743             if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
3744                 (!pTPWnd || (lppop->hWnd != pTPWnd->hwndSelf)))
3745                 DestroyWindow( lppop->hWnd );
3746
3747             if (lppop->items)   /* recursively destroy submenus */
3748             {
3749                 int i;
3750                 MENUITEM *item = lppop->items;
3751                 for (i = lppop->nItems; i > 0; i--, item++)
3752                 {
3753                     if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3754                     MENU_FreeItemData( item );
3755                 }
3756                 HeapFree( SystemHeap, 0, lppop->items );
3757             }
3758             USER_HEAP_FREE( hMenu );
3759             MENU_ReleaseTopPopupWnd();
3760         }
3761         else
3762         {
3763             MENU_ReleaseTopPopupWnd();
3764             return FALSE;
3765         }
3766     }
3767     return (hMenu != MENU_DefSysPopup);
3768 }
3769
3770
3771 /**********************************************************************
3772  *         GetSystemMenu16    (USER.156)
3773  */
3774 HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
3775 {
3776     return GetSystemMenu( hWnd, bRevert );
3777 }
3778
3779
3780 /**********************************************************************
3781  *         GetSystemMenu32    (USER32.291)
3782  */
3783 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3784 {
3785     WND *wndPtr = WIN_FindWndPtr( hWnd );
3786     HMENU retvalue = 0;
3787
3788     if (wndPtr)
3789     {
3790         if( wndPtr->hSysMenu )
3791         {
3792             if( bRevert )
3793             {
3794                 DestroyMenu(wndPtr->hSysMenu); 
3795                 wndPtr->hSysMenu = 0;
3796             }
3797             else
3798             {
3799                 POPUPMENU *menu = (POPUPMENU*) 
3800                            USER_HEAP_LIN_ADDR(wndPtr->hSysMenu);
3801                 if( IS_A_MENU(menu) ) 
3802                 {
3803                    if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3804                       menu->items[0].hSubMenu = MENU_CopySysPopup();
3805                 }
3806                 else 
3807                 {
3808                    WARN("Current sys-menu (%04x) of wnd %04x is broken\n", 
3809                         wndPtr->hSysMenu, hWnd);
3810                    wndPtr->hSysMenu = 0;
3811                 }
3812             }
3813         }
3814
3815         if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3816             wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3817
3818         if( wndPtr->hSysMenu )
3819         {
3820             POPUPMENU *menu;
3821             retvalue = GetSubMenu16(wndPtr->hSysMenu, 0);
3822
3823             /* Store the dummy sysmenu handle to facilitate the refresh */
3824             /* of the close button if the SC_CLOSE item change */
3825             menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(retvalue);
3826             if ( IS_A_MENU(menu) )
3827                menu->hSysMenuOwner = wndPtr->hSysMenu;
3828         }
3829         WIN_ReleaseWndPtr(wndPtr);
3830     }
3831     return retvalue;
3832 }
3833
3834
3835 /*******************************************************************
3836  *         SetSystemMenu16    (USER.280)
3837  */
3838 BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
3839 {
3840     return SetSystemMenu( hwnd, hMenu );
3841 }
3842
3843
3844 /*******************************************************************
3845  *         SetSystemMenu32    (USER32.508)
3846  */
3847 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3848 {
3849     WND *wndPtr = WIN_FindWndPtr(hwnd);
3850
3851     if (wndPtr)
3852     {
3853         if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3854         wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3855         WIN_ReleaseWndPtr(wndPtr);
3856         return TRUE;
3857     }
3858     return FALSE;
3859 }
3860
3861
3862 /**********************************************************************
3863  *         GetMenu16    (USER.157)
3864  */
3865 HMENU16 WINAPI GetMenu16( HWND16 hWnd ) 
3866 {
3867     HMENU16 retvalue;
3868     WND * wndPtr = WIN_FindWndPtr(hWnd);
3869     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) 
3870     {
3871         retvalue = (HMENU16)wndPtr->wIDmenu;
3872         goto END;
3873 }
3874     retvalue = 0;
3875 END:
3876     WIN_ReleaseWndPtr(wndPtr);
3877     return retvalue;
3878 }
3879
3880
3881 /**********************************************************************
3882  *         GetMenu32    (USER32.257)
3883  */
3884 HMENU WINAPI GetMenu( HWND hWnd ) 
3885
3886     HMENU retvalue;
3887     WND * wndPtr = WIN_FindWndPtr(hWnd);
3888     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) 
3889     {
3890         retvalue = (HMENU)wndPtr->wIDmenu;
3891         goto END;
3892     }
3893     retvalue = 0;
3894 END:
3895     WIN_ReleaseWndPtr(wndPtr);
3896     return retvalue;
3897 }
3898
3899
3900 /**********************************************************************
3901  *         SetMenu16    (USER.158)
3902  */
3903 BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
3904 {
3905     return SetMenu( hWnd, hMenu );
3906 }
3907
3908
3909 /**********************************************************************
3910  *         SetMenu32    (USER32.487)
3911  */
3912 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
3913 {
3914     WND * wndPtr = WIN_FindWndPtr(hWnd);
3915
3916     TRACE("(%04x, %04x);\n", hWnd, hMenu);
3917
3918     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
3919     {
3920         if (GetCapture() == hWnd) ReleaseCapture();
3921
3922         wndPtr->wIDmenu = (UINT)hMenu;
3923         if (hMenu != 0)
3924         {
3925             LPPOPUPMENU lpmenu;
3926
3927             if (!(lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
3928             {
3929                 WIN_ReleaseWndPtr(wndPtr);
3930                 return FALSE;
3931             }
3932             lpmenu->hWnd = hWnd;
3933             lpmenu->wFlags &= ~MF_POPUP;  /* Can't be a popup */
3934             lpmenu->Height = 0;  /* Make sure we recalculate the size */
3935         }
3936         if (IsWindowVisible(hWnd))
3937             SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3938                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3939         WIN_ReleaseWndPtr(wndPtr);
3940         return TRUE;
3941     }
3942     WIN_ReleaseWndPtr(wndPtr);
3943     return FALSE;
3944 }
3945
3946
3947
3948 /**********************************************************************
3949  *         GetSubMenu16    (USER.159)
3950  */
3951 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
3952 {
3953     return GetSubMenu( hMenu, nPos );
3954 }
3955
3956
3957 /**********************************************************************
3958  *         GetSubMenu32    (USER32.288)
3959  */
3960 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
3961 {
3962     MENUITEM * lpmi;
3963
3964     if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3965     if (!(lpmi->fType & MF_POPUP)) return 0;
3966     return lpmi->hSubMenu;
3967 }
3968
3969
3970 /**********************************************************************
3971  *         DrawMenuBar16    (USER.160)
3972  */
3973 void WINAPI DrawMenuBar16( HWND16 hWnd )
3974 {
3975     DrawMenuBar( hWnd );
3976 }
3977
3978
3979 /**********************************************************************
3980  *         DrawMenuBar    (USER32.161)
3981  */
3982 BOOL WINAPI DrawMenuBar( HWND hWnd )
3983 {
3984     LPPOPUPMENU lppop;
3985     WND *wndPtr = WIN_FindWndPtr(hWnd);
3986     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
3987     {
3988         lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu);
3989         if (lppop == NULL)
3990         {
3991             WIN_ReleaseWndPtr(wndPtr);
3992             return FALSE;
3993         }
3994
3995         lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
3996         lppop->hwndOwner = hWnd;
3997         SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3998                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3999         WIN_ReleaseWndPtr(wndPtr);
4000         return TRUE;
4001     }
4002     WIN_ReleaseWndPtr(wndPtr);
4003     return FALSE;
4004 }
4005
4006
4007 /***********************************************************************
4008  *           EndMenu   (USER.187) (USER32.175)
4009  */
4010 void WINAPI EndMenu(void)
4011 {
4012     /*
4013      * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
4014      */
4015
4016     fEndMenu = TRUE;
4017 }
4018
4019
4020 /***********************************************************************
4021  *           LookupMenuHandle   (USER.217)
4022  */
4023 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4024 {
4025     HMENU hmenu32 = hmenu;
4026     UINT id32 = id;
4027     if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4028     else return hmenu32;
4029 }
4030
4031
4032 /**********************************************************************
4033  *          LoadMenu16    (USER.150)
4034  */
4035 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, SEGPTR name )
4036 {
4037     HRSRC16 hRsrc;
4038     HGLOBAL16 handle;
4039     HMENU16 hMenu;
4040
4041     if (HIWORD(name))
4042     {
4043         char *str = (char *)PTR_SEG_TO_LIN( name );
4044         TRACE("(%04x,'%s')\n", instance, str );
4045         if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
4046     }
4047     else
4048         TRACE("(%04x,%04x)\n",instance,LOWORD(name));
4049
4050     if (!name) return 0;
4051     
4052     /* check for Win32 module */
4053     if (HIWORD(instance))
4054         return LoadMenuA(instance,PTR_SEG_TO_LIN(name));
4055     instance = GetExePtr( instance );
4056
4057     if (!(hRsrc = FindResource16( instance, name, RT_MENU16 ))) return 0;
4058     if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4059     hMenu = LoadMenuIndirect16(LockResource16(handle));
4060     FreeResource16( handle );
4061     return hMenu;
4062 }
4063
4064
4065 /*****************************************************************
4066  *        LoadMenu32A   (USER32.370)
4067  */
4068 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4069 {
4070     HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4071     if (!hrsrc) return 0;
4072     return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4073 }
4074
4075
4076 /*****************************************************************
4077  *        LoadMenu32W   (USER32.373)
4078  */
4079 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4080 {
4081     HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4082     if (!hrsrc) return 0;
4083     return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4084 }
4085
4086
4087 /**********************************************************************
4088  *          LoadMenuIndirect16    (USER.220)
4089  */
4090 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4091 {
4092     HMENU16 hMenu;
4093     WORD version, offset;
4094     LPCSTR p = (LPCSTR)template;
4095
4096     TRACE("(%p)\n", template );
4097     version = GET_WORD(p);
4098     p += sizeof(WORD);
4099     if (version)
4100     {
4101         WARN("version must be 0 for Win16\n" );
4102         return 0;
4103     }
4104     offset = GET_WORD(p);
4105     p += sizeof(WORD) + offset;
4106     if (!(hMenu = CreateMenu())) return 0;
4107     if (!MENU_ParseResource( p, hMenu, FALSE ))
4108     {
4109         DestroyMenu( hMenu );
4110         return 0;
4111     }
4112     return hMenu;
4113 }
4114
4115
4116 /**********************************************************************
4117  *          LoadMenuIndirect32A    (USER32.371)
4118  */
4119 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4120 {
4121     HMENU16 hMenu;
4122     WORD version, offset;
4123     LPCSTR p = (LPCSTR)template;
4124
4125     TRACE("%p\n", template );
4126     version = GET_WORD(p);
4127     p += sizeof(WORD);
4128     switch (version)
4129       {
4130       case 0:
4131         offset = GET_WORD(p);
4132         p += sizeof(WORD) + offset;
4133         if (!(hMenu = CreateMenu())) return 0;
4134         if (!MENU_ParseResource( p, hMenu, TRUE ))
4135           {
4136             DestroyMenu( hMenu );
4137             return 0;
4138           }
4139         return hMenu;
4140       case 1:
4141         offset = GET_WORD(p);
4142         p += sizeof(WORD) + offset;
4143         if (!(hMenu = CreateMenu())) return 0;
4144         if (!MENUEX_ParseResource( p, hMenu))
4145           {
4146             DestroyMenu( hMenu );
4147             return 0;
4148           }
4149         return hMenu;
4150       default:
4151         ERR("version %d not supported.\n", version);
4152         return 0;
4153       }
4154 }
4155
4156
4157 /**********************************************************************
4158  *          LoadMenuIndirect32W    (USER32.372)
4159  */
4160 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4161 {
4162     /* FIXME: is there anything different between A and W? */
4163     return LoadMenuIndirectA( template );
4164 }
4165
4166
4167 /**********************************************************************
4168  *              IsMenu16    (USER.358)
4169  */
4170 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4171 {
4172     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4173     return IS_A_MENU(menu);
4174 }
4175
4176
4177 /**********************************************************************
4178  *              IsMenu32    (USER32.346)
4179  */
4180 BOOL WINAPI IsMenu(HMENU hmenu)
4181 {
4182     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
4183     return IS_A_MENU(menu);
4184 }
4185
4186 /**********************************************************************
4187  *              GetMenuItemInfo32_common
4188  */
4189
4190 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4191                                         LPMENUITEMINFOA lpmii, BOOL unicode)
4192 {
4193     MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4194
4195     debug_print_menuitem("GetMenuItemInfo32_common: ", menu, "");
4196
4197     if (!menu)
4198         return FALSE;
4199
4200     if (lpmii->fMask & MIIM_TYPE) {
4201         lpmii->fType = menu->fType;
4202         switch (MENU_ITEM_TYPE(menu->fType)) {
4203                 case MF_STRING:
4204                     if (menu->text && lpmii->dwTypeData && lpmii->cch) {
4205                         if (unicode) {
4206                             lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text, lpmii->cch);
4207                             lpmii->cch = lstrlenW((LPWSTR)menu->text);
4208                         } else {
4209                             lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4210                             lpmii->cch = lstrlenA(menu->text);
4211                         }
4212                     }
4213                     break;
4214                 case MF_OWNERDRAW:
4215                 case MF_BITMAP:
4216                     lpmii->dwTypeData = menu->text;
4217                     /* fall through */
4218                 default:
4219                     lpmii->cch = 0;
4220         }
4221     }
4222
4223     if (lpmii->fMask & MIIM_STRING) {
4224         if (unicode) {
4225             lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text, lpmii->cch);
4226             lpmii->cch = lstrlenW((LPWSTR)menu->text);
4227         } else {
4228             lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
4229             lpmii->cch = lstrlenA(menu->text);
4230         }
4231     }
4232
4233     if (lpmii->fMask & MIIM_FTYPE)
4234         lpmii->fType = menu->fType;
4235
4236     if (lpmii->fMask & MIIM_BITMAP)
4237         lpmii->hbmpItem = menu->hbmpItem;
4238
4239     if (lpmii->fMask & MIIM_STATE)
4240         lpmii->fState = menu->fState;
4241
4242     if (lpmii->fMask & MIIM_ID)
4243         lpmii->wID = menu->wID;
4244
4245     if (lpmii->fMask & MIIM_SUBMENU)
4246         lpmii->hSubMenu = menu->hSubMenu;
4247
4248     if (lpmii->fMask & MIIM_CHECKMARKS) {
4249         lpmii->hbmpChecked = menu->hCheckBit;
4250         lpmii->hbmpUnchecked = menu->hUnCheckBit;
4251     }
4252     if (lpmii->fMask & MIIM_DATA)
4253         lpmii->dwItemData = menu->dwItemData;
4254
4255   return TRUE;
4256 }
4257
4258 /**********************************************************************
4259  *              GetMenuItemInfoA    (USER32.264)
4260  */
4261 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4262                                   LPMENUITEMINFOA lpmii)
4263 {
4264     return GetMenuItemInfo_common (hmenu, item, bypos, lpmii, FALSE);
4265 }
4266
4267 /**********************************************************************
4268  *              GetMenuItemInfoW    (USER32.265)
4269  */
4270 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4271                                   LPMENUITEMINFOW lpmii)
4272 {
4273     return GetMenuItemInfo_common (hmenu, item, bypos,
4274                                      (LPMENUITEMINFOA)lpmii, TRUE);
4275 }
4276
4277 /**********************************************************************
4278  *              SetMenuItemInfo32_common
4279  */
4280
4281 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4282                                        const MENUITEMINFOA *lpmii,
4283                                        BOOL unicode)
4284 {
4285     if (!menu) return FALSE;
4286
4287     if (lpmii->fMask & MIIM_TYPE ) {
4288         /* Get rid of old string.  */
4289         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4290             HeapFree(SystemHeap, 0, menu->text);
4291             menu->text = NULL;
4292         }
4293
4294         /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */ 
4295         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4296         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4297
4298         menu->text = lpmii->dwTypeData;
4299
4300         if (IS_STRING_ITEM(menu->fType) && menu->text) {
4301             if (unicode)
4302                 menu->text = HEAP_strdupWtoA(SystemHeap, 0,  (LPWSTR) lpmii->dwTypeData);
4303             else
4304                 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4305         }
4306     }
4307
4308     if (lpmii->fMask & MIIM_FTYPE ) {
4309         /* free the string when the type is changing */
4310         if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4311             HeapFree(SystemHeap, 0, menu->text);
4312             menu->text = NULL;
4313         }
4314         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4315         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4316     }
4317
4318     if (lpmii->fMask & MIIM_STRING ) {
4319         /* free the string when used */
4320         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4321             HeapFree(SystemHeap, 0, menu->text);
4322             if (unicode)
4323                 menu->text = HEAP_strdupWtoA(SystemHeap, 0,  (LPWSTR) lpmii->dwTypeData);
4324             else
4325                 menu->text = HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
4326         }
4327     }
4328
4329     if (lpmii->fMask & MIIM_STATE)
4330     {
4331         /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4332         menu->fState = lpmii->fState;
4333     }
4334
4335     if (lpmii->fMask & MIIM_ID)
4336         menu->wID = lpmii->wID;
4337
4338     if (lpmii->fMask & MIIM_SUBMENU) {
4339         menu->hSubMenu = lpmii->hSubMenu;
4340         if (menu->hSubMenu) {
4341             POPUPMENU *subMenu = (POPUPMENU *)USER_HEAP_LIN_ADDR((UINT16)menu->hSubMenu);
4342             if (IS_A_MENU(subMenu)) {
4343                 subMenu->wFlags |= MF_POPUP;
4344                 menu->fType |= MF_POPUP;
4345             }
4346             else
4347                 /* FIXME: Return an error ? */
4348                 menu->fType &= ~MF_POPUP;
4349         }
4350         else
4351             menu->fType &= ~MF_POPUP;
4352     }
4353
4354     if (lpmii->fMask & MIIM_CHECKMARKS)
4355     {
4356         menu->hCheckBit = lpmii->hbmpChecked;
4357         menu->hUnCheckBit = lpmii->hbmpUnchecked;
4358     }
4359     if (lpmii->fMask & MIIM_DATA)
4360         menu->dwItemData = lpmii->dwItemData;
4361
4362     debug_print_menuitem("SetMenuItemInfo32_common: ", menu, "");
4363     return TRUE;
4364 }
4365
4366 /**********************************************************************
4367  *              SetMenuItemInfo32A    (USER32.491)
4368  */
4369 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4370                                  const MENUITEMINFOA *lpmii) 
4371 {
4372     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4373                                     lpmii, FALSE);
4374 }
4375
4376 /**********************************************************************
4377  *              SetMenuItemInfo32W    (USER32.492)
4378  */
4379 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4380                                  const MENUITEMINFOW *lpmii)
4381 {
4382     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4383                                     (const MENUITEMINFOA*)lpmii, TRUE);
4384 }
4385
4386 /**********************************************************************
4387  *              SetMenuDefaultItem    (USER32.489)
4388  *
4389  */
4390 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4391 {
4392         UINT i;
4393         POPUPMENU *menu;
4394         MENUITEM *item;
4395         
4396         TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4397
4398         if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hmenu))) return FALSE;
4399
4400         /* reset all default-item flags */
4401         item = menu->items;
4402         for (i = 0; i < menu->nItems; i++, item++)
4403         {
4404             item->fState &= ~MFS_DEFAULT;
4405         }
4406         
4407         /* no default item */
4408         if ( -1 == uItem)
4409         {
4410             return TRUE;
4411         }
4412
4413         item = menu->items;
4414         if ( bypos )
4415         {
4416             if ( uItem >= menu->nItems ) return FALSE;
4417             item[uItem].fState |= MFS_DEFAULT;
4418             return TRUE;
4419         }
4420         else
4421         {
4422             for (i = 0; i < menu->nItems; i++, item++)
4423             {
4424                 if (item->wID == uItem)
4425                 {
4426                      item->fState |= MFS_DEFAULT;
4427                      return TRUE;
4428                 }
4429             }
4430                 
4431         }
4432         return FALSE;
4433 }
4434
4435 /**********************************************************************
4436  *              GetMenuDefaultItem    (USER32.260)
4437  */
4438 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4439 {
4440         POPUPMENU *menu;
4441         MENUITEM * item;
4442         UINT i = 0;
4443
4444         TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4445
4446         if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hmenu))) return -1;
4447
4448         /* find default item */
4449         item = menu->items;
4450         
4451         /* empty menu */
4452         if (! item) return -1;
4453         
4454         while ( !( item->fState & MFS_DEFAULT ) )
4455         {
4456             i++; item++;
4457             if  (i >= menu->nItems ) return -1;
4458         }
4459         
4460         /* default: don't return disabled items */
4461         if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4462
4463         /* search rekursiv when needed */
4464         if ( (item->fType & MF_POPUP) &&  (flags & GMDI_GOINTOPOPUPS) )
4465         {
4466             UINT ret;
4467             ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4468             if ( -1 != ret ) return ret;
4469
4470             /* when item not found in submenu, return the popup item */
4471         }
4472         return ( bypos ) ? i : item->wID;
4473
4474 }
4475
4476 /*******************************************************************
4477  *              InsertMenuItem16   (USER.441)
4478  *
4479  * FIXME: untested
4480  */
4481 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4482                                 const MENUITEMINFO16 *mii )
4483 {
4484     MENUITEMINFOA miia;
4485
4486     miia.cbSize        = sizeof(miia);
4487     miia.fMask         = mii->fMask;
4488     miia.dwTypeData    = mii->dwTypeData;
4489     miia.fType         = mii->fType;
4490     miia.fState        = mii->fState;
4491     miia.wID           = mii->wID;
4492     miia.hSubMenu      = mii->hSubMenu;
4493     miia.hbmpChecked   = mii->hbmpChecked;
4494     miia.hbmpUnchecked = mii->hbmpUnchecked;
4495     miia.dwItemData    = mii->dwItemData;
4496     miia.cch           = mii->cch;
4497     if (IS_STRING_ITEM(miia.fType))
4498         miia.dwTypeData = PTR_SEG_TO_LIN(miia.dwTypeData);
4499     return InsertMenuItemA( hmenu, pos, byposition, &miia );
4500 }
4501
4502
4503 /**********************************************************************
4504  *              InsertMenuItem32A    (USER32.323)
4505  */
4506 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4507                                 const MENUITEMINFOA *lpmii)
4508 {
4509     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4510     return SetMenuItemInfo_common(item, lpmii, FALSE);
4511 }
4512
4513
4514 /**********************************************************************
4515  *              InsertMenuItem32W    (USER32.324)
4516  */
4517 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4518                                 const MENUITEMINFOW *lpmii)
4519 {
4520     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4521     return SetMenuItemInfo_common(item, (const MENUITEMINFOA*)lpmii, TRUE);
4522 }
4523
4524 /**********************************************************************
4525  *              CheckMenuRadioItem32    (USER32.47)
4526  */
4527
4528 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4529                                    UINT first, UINT last, UINT check,
4530                                    UINT bypos)
4531 {
4532      MENUITEM *mifirst, *milast, *micheck;
4533      HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4534
4535      TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4536                   hMenu, first, last, check, bypos);
4537
4538      mifirst = MENU_FindItem (&mfirst, &first, bypos);
4539      milast = MENU_FindItem (&mlast, &last, bypos);
4540      micheck = MENU_FindItem (&mcheck, &check, bypos);
4541
4542      if (mifirst == NULL || milast == NULL || micheck == NULL ||
4543          mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4544          micheck > milast || micheck < mifirst)
4545           return FALSE;
4546
4547      while (mifirst <= milast)
4548      {
4549           if (mifirst == micheck)
4550           {
4551                mifirst->fType |= MFT_RADIOCHECK;
4552                mifirst->fState |= MFS_CHECKED;
4553           } else {
4554                mifirst->fType &= ~MFT_RADIOCHECK;
4555                mifirst->fState &= ~MFS_CHECKED;
4556           }
4557           mifirst++;
4558      }
4559
4560      return TRUE;
4561 }
4562
4563 /**********************************************************************
4564  *              CheckMenuRadioItem16    (not a Windows API)
4565  */
4566
4567 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4568                                    UINT16 first, UINT16 last, UINT16 check,
4569                                    BOOL16 bypos)
4570 {
4571      return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4572 }
4573
4574 /**********************************************************************
4575  *              GetMenuItemRect32    (USER32.266)
4576  *
4577  *      ATTENTION: Here, the returned values in rect are the screen 
4578  *                 coordinates of the item just like if the menu was 
4579  *                 always on the upper left side of the application.
4580  *                 
4581  */
4582 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4583                                  LPRECT rect)
4584 {
4585      POPUPMENU *itemMenu;
4586      MENUITEM *item;
4587      HWND referenceHwnd;
4588
4589      TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4590
4591      item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4592      referenceHwnd = hwnd;
4593
4594      if(!hwnd)
4595      {
4596          itemMenu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
4597          if (itemMenu == NULL) 
4598              return FALSE;
4599
4600          if(itemMenu->hWnd == 0)
4601              return FALSE;
4602          referenceHwnd = itemMenu->hWnd;
4603      }
4604
4605      if ((rect == NULL) || (item == NULL)) 
4606          return FALSE;
4607
4608      *rect = item->rect;
4609
4610      MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4611
4612      return TRUE;
4613 }
4614
4615 /**********************************************************************
4616  *              GetMenuItemRect16    (USER.665)
4617  */
4618
4619 BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
4620                                  LPRECT16 rect)
4621 {
4622      RECT r32;
4623      BOOL res;
4624
4625      if (!rect) return FALSE;
4626      res = GetMenuItemRect (hwnd, hMenu, uItem, &r32);
4627      CONV_RECT32TO16 (&r32, rect);
4628      return res;
4629 }
4630
4631 /**********************************************************************
4632  *              SetMenuInfo
4633  *
4634  * FIXME
4635  *      MIM_APPLYTOSUBMENUS
4636  *      actually use the items to draw the menu
4637  */
4638 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4639 {
4640     POPUPMENU *menu;
4641
4642     TRACE("(0x%04x %p)\n", hMenu, lpmi);
4643
4644     if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu=(POPUPMENU*)USER_HEAP_LIN_ADDR(hMenu)))
4645     {
4646
4647         if (lpmi->fMask & MIM_BACKGROUND)
4648             menu->hbrBack = lpmi->hbrBack;
4649
4650         if (lpmi->fMask & MIM_HELPID)
4651             menu->dwContextHelpID = lpmi->dwContextHelpID;
4652
4653         if (lpmi->fMask & MIM_MAXHEIGHT)
4654             menu->cyMax = lpmi->cyMax;
4655
4656         if (lpmi->fMask & MIM_MENUDATA)
4657             menu->dwMenuData = lpmi->dwMenuData;
4658
4659         if (lpmi->fMask & MIM_STYLE)
4660             menu->dwStyle = lpmi->dwStyle;
4661
4662         return TRUE;
4663     }
4664     return FALSE;
4665 }
4666
4667 /**********************************************************************
4668  *              GetMenuInfo
4669  *
4670  *  NOTES
4671  *      win98/NT5.0
4672  *
4673  */
4674 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4675 {   POPUPMENU *menu;
4676
4677     TRACE("(0x%04x %p)\n", hMenu, lpmi);
4678
4679     if (lpmi && (menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu)))
4680     {
4681
4682         if (lpmi->fMask & MIM_BACKGROUND)
4683             lpmi->hbrBack = menu->hbrBack;
4684
4685         if (lpmi->fMask & MIM_HELPID)
4686             lpmi->dwContextHelpID = menu->dwContextHelpID;
4687
4688         if (lpmi->fMask & MIM_MAXHEIGHT)
4689             lpmi->cyMax = menu->cyMax;
4690
4691         if (lpmi->fMask & MIM_MENUDATA)
4692             lpmi->dwMenuData = menu->dwMenuData;
4693
4694         if (lpmi->fMask & MIM_STYLE)
4695             lpmi->dwStyle = menu->dwStyle;
4696
4697         return TRUE;
4698     }
4699     return FALSE;
4700 }
4701
4702 /**********************************************************************
4703  *         SetMenuContextHelpId16    (USER.384)
4704  */
4705 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4706 {
4707         return SetMenuContextHelpId( hMenu, dwContextHelpID );
4708 }
4709
4710
4711 /**********************************************************************
4712  *         SetMenuContextHelpId    (USER32.488)
4713  */
4714 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4715 {
4716     LPPOPUPMENU menu;
4717
4718     TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4719
4720     if ((menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu)))
4721     {
4722         menu->dwContextHelpID = dwContextHelpID;
4723         return TRUE;
4724     }
4725     return FALSE;
4726 }
4727
4728 /**********************************************************************
4729  *         GetMenuContextHelpId16    (USER.385)
4730  */
4731 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4732 {
4733         return GetMenuContextHelpId( hMenu );
4734 }
4735  
4736 /**********************************************************************
4737  *         GetMenuContextHelpId    (USER32.488)
4738  */
4739 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4740 {
4741     LPPOPUPMENU menu;
4742
4743     TRACE("(0x%04x)\n", hMenu);
4744
4745     if ((menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu)))
4746     {
4747         return menu->dwContextHelpID;
4748     }
4749     return 0;
4750 }