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