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