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