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