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