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