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