riched20: Fixed calculation of left indent and first indent paragraph
[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 UINT 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 (!str || !nMaxSiz) return strlenW(item->text);
3299     if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3300         str[nMaxSiz-1] = 0;
3301     TRACE("returning '%s'\n", str );
3302     return strlen(str);
3303 }
3304
3305
3306 /*******************************************************************
3307  *         GetMenuStringW    (USER32.@)
3308  */
3309 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3310                                LPWSTR str, INT nMaxSiz, UINT wFlags )
3311 {
3312     MENUITEM *item;
3313
3314     TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
3315     if (str && nMaxSiz) str[0] = '\0';
3316     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
3317         SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
3318         return 0;
3319     }
3320     if (!str || !nMaxSiz) return item->text ? strlenW(item->text) : 0;
3321     if( !(item->text)) {
3322         str[0] = 0;
3323         return 0;
3324     }
3325     lstrcpynW( str, item->text, nMaxSiz );
3326     return strlenW(str);
3327 }
3328
3329
3330 /**********************************************************************
3331  *         HiliteMenuItem    (USER32.@)
3332  */
3333 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3334                                 UINT wHilite )
3335 {
3336     LPPOPUPMENU menu;
3337     TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
3338     if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3339     if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3340     if (menu->FocusedItem == wItemID) return TRUE;
3341     MENU_HideSubPopups( hWnd, hMenu, FALSE );
3342     MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3343     return TRUE;
3344 }
3345
3346
3347 /**********************************************************************
3348  *         GetMenuState    (USER32.@)
3349  */
3350 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3351 {
3352     MENUITEM *item;
3353     TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, wItemID, wFlags);
3354     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3355     debug_print_menuitem ("  item: ", item, "");
3356     if (item->fType & MF_POPUP)
3357     {
3358         POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3359         if (!menu) return -1;
3360         else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3361     }
3362     else
3363     {
3364         /* We used to (from way back then) mask the result to 0xff.  */
3365         /* I don't know why and it seems wrong as the documented */
3366         /* return flag MF_SEPARATOR is outside that mask.  */
3367         return (item->fType | item->fState);
3368     }
3369 }
3370
3371
3372 /**********************************************************************
3373  *         GetMenuItemCount    (USER32.@)
3374  */
3375 INT WINAPI GetMenuItemCount( HMENU hMenu )
3376 {
3377     LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3378     if (!menu) return -1;
3379     TRACE("(%p) returning %d\n", hMenu, menu->nItems );
3380     return menu->nItems;
3381 }
3382
3383
3384 /**********************************************************************
3385  *         GetMenuItemID    (USER32.@)
3386  */
3387 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3388 {
3389     MENUITEM * lpmi;
3390
3391     if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
3392     if (lpmi->fType & MF_POPUP) return -1;
3393     return lpmi->wID;
3394
3395 }
3396
3397
3398 /*******************************************************************
3399  *         InsertMenuW    (USER32.@)
3400  */
3401 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3402                          UINT_PTR id, LPCWSTR str )
3403 {
3404     MENUITEM *item;
3405
3406     if (IS_STRING_ITEM(flags) && str)
3407         TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3408               hMenu, pos, flags, id, debugstr_w(str) );
3409     else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %p (not a string)\n",
3410                hMenu, pos, flags, id, str );
3411
3412     if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3413
3414     if (!(MENU_SetItemData( item, flags, id, str )))
3415     {
3416         RemoveMenu( hMenu, pos, flags );
3417         return FALSE;
3418     }
3419
3420     if (flags & MF_POPUP)  /* Set the MF_POPUP flag on the popup-menu */
3421         (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
3422
3423     item->hCheckBit = item->hUnCheckBit = 0;
3424     return TRUE;
3425 }
3426
3427
3428 /*******************************************************************
3429  *         InsertMenuA    (USER32.@)
3430  */
3431 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3432                          UINT_PTR id, LPCSTR str )
3433 {
3434     BOOL ret = FALSE;
3435
3436     if (IS_STRING_ITEM(flags) && str)
3437     {
3438         INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3439         LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3440         if (newstr)
3441         {
3442             MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3443             ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3444             HeapFree( GetProcessHeap(), 0, newstr );
3445         }
3446         return ret;
3447     }
3448     else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3449 }
3450
3451
3452 /*******************************************************************
3453  *         AppendMenuA    (USER32.@)
3454  */
3455 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3456                          UINT_PTR id, LPCSTR data )
3457 {
3458     return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3459 }
3460
3461
3462 /*******************************************************************
3463  *         AppendMenuW    (USER32.@)
3464  */
3465 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3466                          UINT_PTR id, LPCWSTR data )
3467 {
3468     return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3469 }
3470
3471
3472 /**********************************************************************
3473  *         RemoveMenu    (USER32.@)
3474  */
3475 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3476 {
3477     LPPOPUPMENU menu;
3478     MENUITEM *item;
3479
3480     TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3481     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3482     if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3483
3484       /* Remove item */
3485
3486     MENU_FreeItemData( item );
3487
3488     if (--menu->nItems == 0)
3489     {
3490         HeapFree( GetProcessHeap(), 0, menu->items );
3491         menu->items = NULL;
3492     }
3493     else
3494     {
3495         while(nPos < menu->nItems)
3496         {
3497             *item = *(item+1);
3498             item++;
3499             nPos++;
3500         }
3501         menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3502                                    menu->nItems * sizeof(MENUITEM) );
3503     }
3504     return TRUE;
3505 }
3506
3507
3508 /**********************************************************************
3509  *         DeleteMenu    (USER32.@)
3510  */
3511 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3512 {
3513     MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3514     if (!item) return FALSE;
3515     if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3516       /* nPos is now the position of the item */
3517     RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3518     return TRUE;
3519 }
3520
3521
3522 /*******************************************************************
3523  *         ModifyMenuW    (USER32.@)
3524  */
3525 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3526                          UINT_PTR id, LPCWSTR str )
3527 {
3528     MENUITEM *item;
3529
3530     if (IS_STRING_ITEM(flags))
3531         TRACE("%p %d %04x %04x %s\n", hMenu, pos, flags, id, debugstr_w(str) );
3532     else
3533         TRACE("%p %d %04x %04x %p\n", hMenu, pos, flags, id, str );
3534
3535     if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3536     MENU_GetMenu(hMenu)->Height = 0; /* force size recalculate */
3537     return MENU_SetItemData( item, flags, id, str );
3538 }
3539
3540
3541 /*******************************************************************
3542  *         ModifyMenuA    (USER32.@)
3543  */
3544 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3545                          UINT_PTR id, LPCSTR str )
3546 {
3547     BOOL ret = FALSE;
3548
3549     if (IS_STRING_ITEM(flags) && str)
3550     {
3551         INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3552         LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3553         if (newstr)
3554         {
3555             MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3556             ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3557             HeapFree( GetProcessHeap(), 0, newstr );
3558         }
3559         return ret;
3560     }
3561     else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3562 }
3563
3564
3565 /**********************************************************************
3566  *         CreatePopupMenu    (USER32.@)
3567  */
3568 HMENU WINAPI CreatePopupMenu(void)
3569 {
3570     HMENU hmenu;
3571     POPUPMENU *menu;
3572
3573     if (!(hmenu = CreateMenu())) return 0;
3574     menu = MENU_GetMenu( hmenu );
3575     menu->wFlags |= MF_POPUP;
3576     menu->bTimeToHide = FALSE;
3577     return hmenu;
3578 }
3579
3580
3581 /**********************************************************************
3582  *         GetMenuCheckMarkDimensions    (USER.417)
3583  *         GetMenuCheckMarkDimensions    (USER32.@)
3584  */
3585 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3586 {
3587     return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3588 }
3589
3590
3591 /**********************************************************************
3592  *         SetMenuItemBitmaps    (USER32.@)
3593  */
3594 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3595                                     HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3596 {
3597     MENUITEM *item;
3598     TRACE("(%p, %04x, %04x, %p, %p)\n",
3599           hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3600     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3601
3602     if (!hNewCheck && !hNewUnCheck)
3603     {
3604         item->fState &= ~MF_USECHECKBITMAPS;
3605     }
3606     else  /* Install new bitmaps */
3607     {
3608         item->hCheckBit = hNewCheck;
3609         item->hUnCheckBit = hNewUnCheck;
3610         item->fState |= MF_USECHECKBITMAPS;
3611     }
3612     return TRUE;
3613 }
3614
3615
3616 /**********************************************************************
3617  *         CreateMenu    (USER32.@)
3618  */
3619 HMENU WINAPI CreateMenu(void)
3620 {
3621     HMENU hMenu;
3622     LPPOPUPMENU menu;
3623     if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3624     menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3625
3626     ZeroMemory(menu, sizeof(POPUPMENU));
3627     menu->wMagic = MENU_MAGIC;
3628     menu->FocusedItem = NO_SELECTED_ITEM;
3629     menu->bTimeToHide = FALSE;
3630
3631     TRACE("return %p\n", hMenu );
3632
3633     return hMenu;
3634 }
3635
3636
3637 /**********************************************************************
3638  *         DestroyMenu    (USER32.@)
3639  */
3640 BOOL WINAPI DestroyMenu( HMENU hMenu )
3641 {
3642     LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3643
3644     TRACE("(%p)\n", hMenu);
3645
3646
3647     if (!lppop) return FALSE;
3648
3649     lppop->wMagic = 0;  /* Mark it as destroyed */
3650
3651     /* DestroyMenu should not destroy system menu popup owner */
3652     if ((lppop->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && lppop->hWnd)
3653     {
3654         DestroyWindow( lppop->hWnd );
3655         lppop->hWnd = 0;
3656     }
3657
3658     if (lppop->items) /* recursively destroy submenus */
3659     {
3660         int i;
3661         MENUITEM *item = lppop->items;
3662         for (i = lppop->nItems; i > 0; i--, item++)
3663         {
3664             if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3665             MENU_FreeItemData( item );
3666         }
3667         HeapFree( GetProcessHeap(), 0, lppop->items );
3668     }
3669     USER_HEAP_FREE( hMenu );
3670     return TRUE;
3671 }
3672
3673
3674 /**********************************************************************
3675  *         GetSystemMenu    (USER32.@)
3676  */
3677 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3678 {
3679     WND *wndPtr = WIN_GetPtr( hWnd );
3680     HMENU retvalue = 0;
3681
3682     if (wndPtr == WND_DESKTOP) return 0;
3683     if (wndPtr == WND_OTHER_PROCESS)
3684     {
3685         if (IsWindow( hWnd )) FIXME( "not supported on other process window %p\n", hWnd );
3686     }
3687     else if (wndPtr)
3688     {
3689         if (wndPtr->hSysMenu && bRevert)
3690         {
3691             DestroyMenu(wndPtr->hSysMenu);
3692             wndPtr->hSysMenu = 0;
3693         }
3694
3695         if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3696             wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, 0 );
3697
3698         if( wndPtr->hSysMenu )
3699         {
3700             POPUPMENU *menu;
3701             retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3702
3703             /* Store the dummy sysmenu handle to facilitate the refresh */
3704             /* of the close button if the SC_CLOSE item change */
3705             menu = MENU_GetMenu(retvalue);
3706             if ( menu )
3707                menu->hSysMenuOwner = wndPtr->hSysMenu;
3708         }
3709         WIN_ReleasePtr( wndPtr );
3710     }
3711     return bRevert ? 0 : retvalue;
3712 }
3713
3714
3715 /*******************************************************************
3716  *         SetSystemMenu    (USER32.@)
3717  */
3718 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3719 {
3720     WND *wndPtr = WIN_GetPtr( hwnd );
3721
3722     if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
3723     {
3724         if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3725         wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3726         WIN_ReleasePtr( wndPtr );
3727         return TRUE;
3728     }
3729     return FALSE;
3730 }
3731
3732
3733 /**********************************************************************
3734  *         GetMenu    (USER32.@)
3735  */
3736 HMENU WINAPI GetMenu( HWND hWnd )
3737 {
3738     HMENU retvalue = (HMENU)GetWindowLongPtrW( hWnd, GWLP_ID );
3739     TRACE("for %p returning %p\n", hWnd, retvalue);
3740     return retvalue;
3741 }
3742
3743 /**********************************************************************
3744  *         GetMenuBarInfo    (USER32.@)
3745  */
3746 BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi )
3747 {
3748     FIXME( "(%p,0x%08lx,0x%08lx,%p)\n", hwnd, idObject, idItem, pmbi );
3749     return FALSE;
3750 }
3751
3752 /**********************************************************************
3753  *         MENU_SetMenu
3754  *
3755  * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
3756  * SetWindowPos call that would result if SetMenu were called directly.
3757  */
3758 BOOL MENU_SetMenu( HWND hWnd, HMENU hMenu )
3759 {
3760     TRACE("(%p, %p);\n", hWnd, hMenu);
3761
3762     if (hMenu && !IsMenu(hMenu))
3763     {
3764         WARN("hMenu %p is not a menu handle\n", hMenu);
3765         SetLastError(ERROR_INVALID_MENU_HANDLE);
3766         return FALSE;
3767     }
3768     if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
3769         return FALSE;
3770
3771     hWnd = WIN_GetFullHandle( hWnd );
3772     if (GetCapture() == hWnd) MENU_SetCapture(0);  /* release the capture */
3773
3774     if (hMenu != 0)
3775     {
3776         LPPOPUPMENU lpmenu;
3777
3778         if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
3779
3780         lpmenu->hWnd = hWnd;
3781         lpmenu->Height = 0;  /* Make sure we recalculate the size */
3782     }
3783     SetWindowLongPtrW( hWnd, GWLP_ID, (LONG_PTR)hMenu );
3784     return TRUE;
3785 }
3786
3787
3788 /**********************************************************************
3789  *         SetMenu    (USER32.@)
3790  */
3791 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
3792 {   
3793     if(!MENU_SetMenu(hWnd, hMenu))
3794         return FALSE;
3795  
3796     SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3797                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3798     return TRUE;
3799 }
3800
3801
3802 /**********************************************************************
3803  *         GetSubMenu    (USER32.@)
3804  */
3805 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
3806 {
3807     MENUITEM * lpmi;
3808
3809     if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return 0;
3810     if (!(lpmi->fType & MF_POPUP)) return 0;
3811     return lpmi->hSubMenu;
3812 }
3813
3814
3815 /**********************************************************************
3816  *         DrawMenuBar    (USER32.@)
3817  */
3818 BOOL WINAPI DrawMenuBar( HWND hWnd )
3819 {
3820     LPPOPUPMENU lppop;
3821     HMENU hMenu = GetMenu(hWnd);
3822
3823     if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd, GWL_STYLE )))
3824         return FALSE;
3825     if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
3826
3827     lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
3828     lppop->hwndOwner = hWnd;
3829     SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3830                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3831     return TRUE;
3832 }
3833
3834 /***********************************************************************
3835  *           DrawMenuBarTemp   (USER32.@)
3836  *
3837  * UNDOCUMENTED !!
3838  *
3839  * called by W98SE desk.cpl Control Panel Applet
3840  *
3841  * Not 100% sure about the param names, but close.
3842  */
3843 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont)
3844 {
3845     LPPOPUPMENU lppop;
3846     UINT i,retvalue;
3847     HFONT hfontOld = 0;
3848     BOOL flat_menu = FALSE;
3849
3850     SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
3851
3852     if (!hMenu)
3853         hMenu = GetMenu(hwnd);
3854
3855     if (!hFont)
3856         hFont = get_menu_font(FALSE);
3857
3858     lppop = MENU_GetMenu( hMenu );
3859     if (lppop == NULL || lprect == NULL)
3860     {
3861         retvalue = GetSystemMetrics(SM_CYMENU);
3862         goto END;
3863     }
3864
3865     TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont);
3866
3867     hfontOld = SelectObject( hDC, hFont);
3868
3869     if (lppop->Height == 0)
3870         MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
3871
3872     lprect->bottom = lprect->top + lppop->Height;
3873
3874     FillRect(hDC, lprect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU) );
3875
3876     SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE));
3877     MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
3878     LineTo( hDC, lprect->right, lprect->bottom );
3879
3880     if (lppop->nItems == 0)
3881     {
3882         retvalue = GetSystemMetrics(SM_CYMENU);
3883         goto END;
3884     }
3885
3886     for (i = 0; i < lppop->nItems; i++)
3887     {
3888         MENU_DrawMenuItem( hwnd, hMenu, hwnd,
3889                            hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
3890     }
3891     retvalue = lppop->Height;
3892
3893 END:
3894     if (hfontOld) SelectObject (hDC, hfontOld);
3895     return retvalue;
3896 }
3897
3898 /***********************************************************************
3899  *           EndMenu   (USER.187)
3900  *           EndMenu   (USER32.@)
3901  */
3902 void WINAPI EndMenu(void)
3903 {
3904     /* if we are in the menu code, and it is active */
3905     if (!fEndMenu && top_popup)
3906     {
3907         /* terminate the menu handling code */
3908         fEndMenu = TRUE;
3909
3910         /* needs to be posted to wakeup the internal menu handler */
3911         /* which will now terminate the menu, in the event that */
3912         /* the main window was minimized, or lost focus, so we */
3913         /* don't end up with an orphaned menu */
3914         PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
3915     }
3916 }
3917
3918
3919 /***********************************************************************
3920  *           LookupMenuHandle   (USER.217)
3921  */
3922 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
3923 {
3924     HMENU hmenu32 = HMENU_32(hmenu);
3925     UINT id32 = id;
3926     if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
3927     else return HMENU_16(hmenu32);
3928 }
3929
3930
3931 /**********************************************************************
3932  *          LoadMenu    (USER.150)
3933  */
3934 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
3935 {
3936     HRSRC16 hRsrc;
3937     HGLOBAL16 handle;
3938     HMENU16 hMenu;
3939
3940     if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
3941     if (!name) return 0;
3942
3943     instance = GetExePtr( instance );
3944     if (!(hRsrc = FindResource16( instance, name, (LPSTR)RT_MENU ))) return 0;
3945     if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
3946     hMenu = LoadMenuIndirect16(LockResource16(handle));
3947     FreeResource16( handle );
3948     return hMenu;
3949 }
3950
3951
3952 /*****************************************************************
3953  *        LoadMenuA   (USER32.@)
3954  */
3955 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
3956 {
3957     HRSRC hrsrc = FindResourceA( instance, name, (LPSTR)RT_MENU );
3958     if (!hrsrc) return 0;
3959     return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
3960 }
3961
3962
3963 /*****************************************************************
3964  *        LoadMenuW   (USER32.@)
3965  */
3966 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
3967 {
3968     HRSRC hrsrc = FindResourceW( instance, name, (LPWSTR)RT_MENU );
3969     if (!hrsrc) return 0;
3970     return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
3971 }
3972
3973
3974 /**********************************************************************
3975  *          LoadMenuIndirect    (USER.220)
3976  */
3977 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
3978 {
3979     HMENU hMenu;
3980     WORD version, offset;
3981     LPCSTR p = (LPCSTR)template;
3982
3983     TRACE("(%p)\n", template );
3984     version = GET_WORD(p);
3985     p += sizeof(WORD);
3986     if (version)
3987     {
3988         WARN("version must be 0 for Win16\n" );
3989         return 0;
3990     }
3991     offset = GET_WORD(p);
3992     p += sizeof(WORD) + offset;
3993     if (!(hMenu = CreateMenu())) return 0;
3994     if (!MENU_ParseResource( p, hMenu, FALSE ))
3995     {
3996         DestroyMenu( hMenu );
3997         return 0;
3998     }
3999     return HMENU_16(hMenu);
4000 }
4001
4002
4003 /**********************************************************************
4004  *          LoadMenuIndirectW    (USER32.@)
4005  */
4006 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4007 {
4008     HMENU hMenu;
4009     WORD version, offset;
4010     LPCSTR p = (LPCSTR)template;
4011
4012     version = GET_WORD(p);
4013     p += sizeof(WORD);
4014     TRACE("%p, ver %d\n", template, version );
4015     switch (version)
4016     {
4017       case 0: /* standard format is version of 0 */
4018         offset = GET_WORD(p);
4019         p += sizeof(WORD) + offset;
4020         if (!(hMenu = CreateMenu())) return 0;
4021         if (!MENU_ParseResource( p, hMenu, TRUE ))
4022           {
4023             DestroyMenu( hMenu );
4024             return 0;
4025           }
4026         return hMenu;
4027       case 1: /* extended format is version of 1 */
4028         offset = GET_WORD(p);
4029         p += sizeof(WORD) + offset;
4030         if (!(hMenu = CreateMenu())) return 0;
4031         if (!MENUEX_ParseResource( p, hMenu))
4032           {
4033             DestroyMenu( hMenu );
4034             return 0;
4035           }
4036         return hMenu;
4037       default:
4038         ERR("version %d not supported.\n", version);
4039         return 0;
4040     }
4041 }
4042
4043
4044 /**********************************************************************
4045  *          LoadMenuIndirectA    (USER32.@)
4046  */
4047 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4048 {
4049     return LoadMenuIndirectW( template );
4050 }
4051
4052
4053 /**********************************************************************
4054  *              IsMenu    (USER32.@)
4055  */
4056 BOOL WINAPI IsMenu(HMENU hmenu)
4057 {
4058     LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4059     return menu != NULL;
4060 }
4061
4062 /**********************************************************************
4063  *              GetMenuItemInfo_common
4064  */
4065
4066 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4067                                         LPMENUITEMINFOW lpmii, BOOL unicode)
4068 {
4069     MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4070
4071     debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4072
4073     if (!menu)
4074         return FALSE;
4075     
4076     if( lpmii->fMask & MIIM_TYPE) {
4077         if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4078             SetLastError( ERROR_INVALID_PARAMETER);
4079             return FALSE;
4080         }
4081         lpmii->fType = menu->fType & ~MF_POPUP;
4082         if( menu->hbmpItem) lpmii->fType |= MFT_BITMAP;
4083         lpmii->hbmpItem = menu->hbmpItem;
4084         if( lpmii->fType & MFT_BITMAP) {
4085             lpmii->dwTypeData = (LPWSTR) menu->hbmpItem;
4086             lpmii->cch = 0;
4087         } else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR)) {
4088             lpmii->dwTypeData = 0;
4089             lpmii->cch = 0;
4090         }
4091     }
4092
4093     /* copy the text string */
4094     if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING))) {
4095          if( !menu->text ) {
4096                 if(lpmii->dwTypeData && lpmii->cch) {
4097                     lpmii->cch = 0;
4098                     if( unicode)
4099                         *((WCHAR *)lpmii->dwTypeData) = 0;
4100                     else
4101                         *((CHAR *)lpmii->dwTypeData) = 0;
4102                 }
4103          } else {
4104             int len;
4105             if (unicode)
4106             {
4107                 len = strlenW(menu->text);
4108                 if(lpmii->dwTypeData && lpmii->cch)
4109                     lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4110             }
4111             else
4112             {
4113                 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL,
4114                         0, NULL, NULL ) - 1;
4115                 if(lpmii->dwTypeData && lpmii->cch)
4116                     if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4117                             (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4118                         ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
4119             }
4120             /* if we've copied a substring we return its length */
4121             if(lpmii->dwTypeData && lpmii->cch)
4122                 if (lpmii->cch <= len + 1)
4123                     lpmii->cch--;
4124                 else
4125                     lpmii->cch = len;
4126             else /* return length of string */
4127                 lpmii->cch = len;
4128         }
4129     }
4130
4131     if (lpmii->fMask & MIIM_FTYPE)
4132         lpmii->fType = menu->fType & ~MF_POPUP;
4133
4134     if (lpmii->fMask & MIIM_BITMAP)
4135         lpmii->hbmpItem = menu->hbmpItem;
4136
4137     if (lpmii->fMask & MIIM_STATE)
4138         lpmii->fState = menu->fState;
4139
4140     if (lpmii->fMask & MIIM_ID)
4141         lpmii->wID = menu->wID;
4142
4143     if (lpmii->fMask & MIIM_SUBMENU)
4144         lpmii->hSubMenu = menu->hSubMenu;
4145     else
4146         lpmii->hSubMenu = 0; /* hSubMenu is always cleared */
4147
4148     if (lpmii->fMask & MIIM_CHECKMARKS) {
4149         lpmii->hbmpChecked = menu->hCheckBit;
4150         lpmii->hbmpUnchecked = menu->hUnCheckBit;
4151     }
4152     if (lpmii->fMask & MIIM_DATA)
4153         lpmii->dwItemData = menu->dwItemData;
4154
4155   return TRUE;
4156 }
4157
4158 /**********************************************************************
4159  *              GetMenuItemInfoA    (USER32.@)
4160  */
4161 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4162                                   LPMENUITEMINFOA lpmii)
4163 {
4164     BOOL ret;
4165     MENUITEMINFOA mii;
4166     if( lpmii->cbSize != sizeof( mii) &&
4167             lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4168         SetLastError( ERROR_INVALID_PARAMETER);
4169         return FALSE;
4170     }
4171     memcpy( &mii, lpmii, lpmii->cbSize);
4172     mii.cbSize = sizeof( mii);
4173     ret = GetMenuItemInfo_common (hmenu, item, bypos,
4174                                     (LPMENUITEMINFOW)&mii, FALSE);
4175     mii.cbSize = lpmii->cbSize;
4176     memcpy( lpmii, &mii, mii.cbSize);
4177     return ret;
4178 }
4179
4180 /**********************************************************************
4181  *              GetMenuItemInfoW    (USER32.@)
4182  */
4183 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4184                                   LPMENUITEMINFOW lpmii)
4185 {
4186     BOOL ret;
4187     MENUITEMINFOW mii;
4188     if( lpmii->cbSize != sizeof( mii) &&
4189             lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4190         SetLastError( ERROR_INVALID_PARAMETER);
4191         return FALSE;
4192     }
4193     memcpy( &mii, lpmii, lpmii->cbSize);
4194     mii.cbSize = sizeof( mii);
4195     ret = GetMenuItemInfo_common (hmenu, item, bypos, &mii, TRUE);
4196     mii.cbSize = lpmii->cbSize;
4197     memcpy( lpmii, &mii, mii.cbSize);
4198     return ret;
4199 }
4200
4201
4202 /* set a menu item text from a ASCII or Unicode string */
4203 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4204 {
4205     if (!text)
4206         menu->text = NULL;
4207     else if (unicode)
4208     {
4209         if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4210             strcpyW( menu->text, text );
4211     }
4212     else
4213     {
4214         LPCSTR str = (LPCSTR)text;
4215         int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4216         if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4217             MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4218     }
4219 }
4220
4221
4222 /**********************************************************************
4223  *              SetMenuItemInfo_common
4224  */
4225
4226 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4227                                        const MENUITEMINFOW *lpmii,
4228                                        BOOL unicode)
4229 {
4230     if (!menu) return FALSE;
4231
4232     debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4233
4234     if (lpmii->fMask & MIIM_TYPE ) {
4235         if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
4236             SetLastError( ERROR_INVALID_PARAMETER);
4237             return FALSE;
4238         }
4239         /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4240         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4241         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4242
4243         if (IS_STRING_ITEM(menu->fType)) {
4244             HeapFree(GetProcessHeap(), 0, menu->text);
4245             set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4246         } else if( (menu->fType) & MFT_BITMAP)
4247                 menu->hbmpItem = (HBITMAP)lpmii->dwTypeData;
4248     }
4249
4250     if (lpmii->fMask & MIIM_FTYPE ) {
4251         if(( lpmii->fType & MFT_BITMAP)) {
4252             SetLastError( ERROR_INVALID_PARAMETER);
4253             return FALSE;
4254         }
4255         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4256         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4257     }
4258     if (lpmii->fMask & MIIM_STRING ) {
4259         /* free the string when used */
4260         HeapFree(GetProcessHeap(), 0, menu->text);
4261         set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4262     }
4263
4264     if (lpmii->fMask & MIIM_STATE)
4265     {
4266         /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4267         menu->fState = lpmii->fState;
4268     }
4269
4270     if (lpmii->fMask & MIIM_ID)
4271         menu->wID = lpmii->wID;
4272
4273     if (lpmii->fMask & MIIM_SUBMENU) {
4274         menu->hSubMenu = lpmii->hSubMenu;
4275         if (menu->hSubMenu) {
4276             POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
4277             if (subMenu) {
4278                 subMenu->wFlags |= MF_POPUP;
4279                 menu->fType |= MF_POPUP;
4280             }
4281             else {
4282                 SetLastError( ERROR_INVALID_PARAMETER);
4283                 return FALSE;
4284             }
4285         }
4286         else
4287             menu->fType &= ~MF_POPUP;
4288     }
4289
4290     if (lpmii->fMask & MIIM_CHECKMARKS)
4291     {
4292         if (lpmii->fType & MFT_RADIOCHECK)
4293             menu->fType |= MFT_RADIOCHECK;
4294
4295         menu->hCheckBit = lpmii->hbmpChecked;
4296         menu->hUnCheckBit = lpmii->hbmpUnchecked;
4297     }
4298     if (lpmii->fMask & MIIM_DATA)
4299         menu->dwItemData = lpmii->dwItemData;
4300
4301     if (lpmii->fMask & MIIM_BITMAP)
4302         menu->hbmpItem = lpmii->hbmpItem;
4303
4304     if( !menu->text && !(menu->fType & MFT_OWNERDRAW) && !menu->hbmpItem)
4305         menu->fType |= MFT_SEPARATOR;
4306
4307     debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4308     return TRUE;
4309 }
4310
4311 /**********************************************************************
4312  *              SetMenuItemInfoA    (USER32.@)
4313  */
4314 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4315                                  const MENUITEMINFOA *lpmii)
4316 {
4317     MENUITEMINFOA mii;
4318     if( lpmii->cbSize != sizeof( mii) &&
4319             lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4320         SetLastError( ERROR_INVALID_PARAMETER);
4321         return FALSE;
4322     }
4323     memcpy( &mii, lpmii, lpmii->cbSize);
4324     if( lpmii->cbSize != sizeof( mii)) {
4325         mii.cbSize = sizeof( mii);
4326         mii.hbmpItem = NULL;
4327     }
4328     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4329                                     (const MENUITEMINFOW *)&mii, FALSE);
4330 }
4331
4332 /**********************************************************************
4333  *              SetMenuItemInfoW    (USER32.@)
4334  */
4335 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4336                                  const MENUITEMINFOW *lpmii)
4337 {
4338     MENUITEMINFOW mii;
4339     if( lpmii->cbSize != sizeof( mii) &&
4340             lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4341         SetLastError( ERROR_INVALID_PARAMETER);
4342         return FALSE;
4343     }
4344     memcpy( &mii, lpmii, lpmii->cbSize);
4345     if( lpmii->cbSize != sizeof( mii)) {
4346         mii.cbSize = sizeof( mii);
4347         mii.hbmpItem = NULL;
4348     }
4349     return SetMenuItemInfo_common(MENU_FindItem(&hmenu,
4350                 &item, bypos? MF_BYPOSITION : 0), &mii, TRUE);
4351 }
4352
4353 /**********************************************************************
4354  *              SetMenuDefaultItem    (USER32.@)
4355  *
4356  */
4357 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4358 {
4359         UINT i;
4360         POPUPMENU *menu;
4361         MENUITEM *item;
4362
4363         TRACE("(%p,%d,%d)\n", hmenu, uItem, bypos);
4364
4365         if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4366
4367         /* reset all default-item flags */
4368         item = menu->items;
4369         for (i = 0; i < menu->nItems; i++, item++)
4370         {
4371             item->fState &= ~MFS_DEFAULT;
4372         }
4373
4374         /* no default item */
4375         if ( -1 == uItem)
4376         {
4377             return TRUE;
4378         }
4379
4380         item = menu->items;
4381         if ( bypos )
4382         {
4383             if ( uItem >= menu->nItems ) return FALSE;
4384             item[uItem].fState |= MFS_DEFAULT;
4385             return TRUE;
4386         }
4387         else
4388         {
4389             for (i = 0; i < menu->nItems; i++, item++)
4390             {
4391                 if (item->wID == uItem)
4392                 {
4393                      item->fState |= MFS_DEFAULT;
4394                      return TRUE;
4395                 }
4396             }
4397
4398         }
4399         return FALSE;
4400 }
4401
4402 /**********************************************************************
4403  *              GetMenuDefaultItem    (USER32.@)
4404  */
4405 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4406 {
4407         POPUPMENU *menu;
4408         MENUITEM * item;
4409         UINT i = 0;
4410
4411         TRACE("(%p,%d,%d)\n", hmenu, bypos, flags);
4412
4413         if (!(menu = MENU_GetMenu(hmenu))) return -1;
4414
4415         /* find default item */
4416         item = menu->items;
4417
4418         /* empty menu */
4419         if (! item) return -1;
4420
4421         while ( !( item->fState & MFS_DEFAULT ) )
4422         {
4423             i++; item++;
4424             if  (i >= menu->nItems ) return -1;
4425         }
4426
4427         /* default: don't return disabled items */
4428         if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4429
4430         /* search rekursiv when needed */
4431         if ( (item->fType & MF_POPUP) &&  (flags & GMDI_GOINTOPOPUPS) )
4432         {
4433             UINT ret;
4434             ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4435             if ( -1 != ret ) return ret;
4436
4437             /* when item not found in submenu, return the popup item */
4438         }
4439         return ( bypos ) ? i : item->wID;
4440
4441 }
4442
4443
4444 /**********************************************************************
4445  *              InsertMenuItemA    (USER32.@)
4446  */
4447 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4448                                 const MENUITEMINFOA *lpmii)
4449 {
4450     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4451     MENUITEMINFOA mii;
4452     if( lpmii->cbSize != sizeof( mii) &&
4453             lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4454         SetLastError( ERROR_INVALID_PARAMETER);
4455         return FALSE;
4456     }
4457     memcpy( &mii, lpmii, lpmii->cbSize);
4458     if( lpmii->cbSize != sizeof( mii)) {
4459         mii.cbSize = sizeof( mii);
4460         mii.hbmpItem = NULL;
4461     }
4462     return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)&mii, FALSE);
4463 }
4464
4465
4466 /**********************************************************************
4467  *              InsertMenuItemW    (USER32.@)
4468  */
4469 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4470                                 const MENUITEMINFOW *lpmii)
4471 {
4472     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4473     MENUITEMINFOW mii;
4474     if( lpmii->cbSize != sizeof( mii) &&
4475             lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
4476         SetLastError( ERROR_INVALID_PARAMETER);
4477         return FALSE;
4478     }
4479     memcpy( &mii, lpmii, lpmii->cbSize);
4480     if( lpmii->cbSize != sizeof( mii)) {
4481         mii.cbSize = sizeof( mii);
4482         mii.hbmpItem = NULL;
4483     }
4484     return SetMenuItemInfo_common(item, &mii, TRUE);
4485 }
4486
4487 /**********************************************************************
4488  *              CheckMenuRadioItem    (USER32.@)
4489  */
4490
4491 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4492                                    UINT first, UINT last, UINT check,
4493                                    UINT bypos)
4494 {
4495      MENUITEM *mifirst, *milast, *micheck;
4496      HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4497
4498      TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos);
4499
4500      mifirst = MENU_FindItem (&mfirst, &first, bypos);
4501      milast = MENU_FindItem (&mlast, &last, bypos);
4502      micheck = MENU_FindItem (&mcheck, &check, bypos);
4503
4504      if (mifirst == NULL || milast == NULL || micheck == NULL ||
4505          mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4506          micheck > milast || micheck < mifirst)
4507           return FALSE;
4508
4509      while (mifirst <= milast)
4510      {
4511           if (mifirst == micheck)
4512           {
4513                mifirst->fType |= MFT_RADIOCHECK;
4514                mifirst->fState |= MFS_CHECKED;
4515           } else {
4516                mifirst->fType &= ~MFT_RADIOCHECK;
4517                mifirst->fState &= ~MFS_CHECKED;
4518           }
4519           mifirst++;
4520      }
4521
4522      return TRUE;
4523 }
4524
4525
4526 /**********************************************************************
4527  *              GetMenuItemRect    (USER32.@)
4528  *
4529  *      ATTENTION: Here, the returned values in rect are the screen
4530  *                 coordinates of the item just like if the menu was
4531  *                 always on the upper left side of the application.
4532  *
4533  */
4534 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4535                                  LPRECT rect)
4536 {
4537      POPUPMENU *itemMenu;
4538      MENUITEM *item;
4539      HWND referenceHwnd;
4540
4541      TRACE("(%p,%p,%d,%p)\n", hwnd, hMenu, uItem, rect);
4542
4543      item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4544      referenceHwnd = hwnd;
4545
4546      if(!hwnd)
4547      {
4548          itemMenu = MENU_GetMenu(hMenu);
4549          if (itemMenu == NULL)
4550              return FALSE;
4551
4552          if(itemMenu->hWnd == 0)
4553              return FALSE;
4554          referenceHwnd = itemMenu->hWnd;
4555      }
4556
4557      if ((rect == NULL) || (item == NULL))
4558          return FALSE;
4559
4560      *rect = item->rect;
4561
4562      MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4563
4564      return TRUE;
4565 }
4566
4567
4568 /**********************************************************************
4569  *              SetMenuInfo    (USER32.@)
4570  *
4571  * FIXME
4572  *      MIM_APPLYTOSUBMENUS
4573  *      actually use the items to draw the menu
4574  */
4575 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4576 {
4577     POPUPMENU *menu;
4578
4579     TRACE("(%p %p)\n", hMenu, lpmi);
4580
4581     if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4582     {
4583
4584         if (lpmi->fMask & MIM_BACKGROUND)
4585             menu->hbrBack = lpmi->hbrBack;
4586
4587         if (lpmi->fMask & MIM_HELPID)
4588             menu->dwContextHelpID = lpmi->dwContextHelpID;
4589
4590         if (lpmi->fMask & MIM_MAXHEIGHT)
4591             menu->cyMax = lpmi->cyMax;
4592
4593         if (lpmi->fMask & MIM_MENUDATA)
4594             menu->dwMenuData = lpmi->dwMenuData;
4595
4596         if (lpmi->fMask & MIM_STYLE)
4597         {
4598             menu->dwStyle = lpmi->dwStyle;
4599             if (menu->dwStyle & MNS_AUTODISMISS) FIXME("MNS_AUTODISMISS unimplemented\n");
4600             if (menu->dwStyle & MNS_DRAGDROP) FIXME("MNS_DRAGDROP unimplemented\n");
4601             if (menu->dwStyle & MNS_MODELESS) FIXME("MNS_MODELESS unimplemented\n");
4602             if (menu->dwStyle & MNS_NOCHECK) FIXME("MNS_NOCHECK unimplemented\n");
4603             if (menu->dwStyle & MNS_NOTIFYBYPOS) FIXME("MNS_NOTIFYBYPOS unimplemented\n");
4604         }
4605
4606         return TRUE;
4607     }
4608     return FALSE;
4609 }
4610
4611 /**********************************************************************
4612  *              GetMenuInfo    (USER32.@)
4613  *
4614  *  NOTES
4615  *      win98/NT5.0
4616  *
4617  */
4618 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4619 {   POPUPMENU *menu;
4620
4621     TRACE("(%p %p)\n", hMenu, lpmi);
4622
4623     if (lpmi && (menu = MENU_GetMenu(hMenu)))
4624     {
4625
4626         if (lpmi->fMask & MIM_BACKGROUND)
4627             lpmi->hbrBack = menu->hbrBack;
4628
4629         if (lpmi->fMask & MIM_HELPID)
4630             lpmi->dwContextHelpID = menu->dwContextHelpID;
4631
4632         if (lpmi->fMask & MIM_MAXHEIGHT)
4633             lpmi->cyMax = menu->cyMax;
4634
4635         if (lpmi->fMask & MIM_MENUDATA)
4636             lpmi->dwMenuData = menu->dwMenuData;
4637
4638         if (lpmi->fMask & MIM_STYLE)
4639             lpmi->dwStyle = menu->dwStyle;
4640
4641         return TRUE;
4642     }
4643     return FALSE;
4644 }
4645
4646
4647 /**********************************************************************
4648  *         SetMenuContextHelpId    (USER32.@)
4649  */
4650 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4651 {
4652     LPPOPUPMENU menu;
4653
4654     TRACE("(%p 0x%08lx)\n", hMenu, dwContextHelpID);
4655
4656     if ((menu = MENU_GetMenu(hMenu)))
4657     {
4658         menu->dwContextHelpID = dwContextHelpID;
4659         return TRUE;
4660     }
4661     return FALSE;
4662 }
4663
4664
4665 /**********************************************************************
4666  *         GetMenuContextHelpId    (USER32.@)
4667  */
4668 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4669 {
4670     LPPOPUPMENU menu;
4671
4672     TRACE("(%p)\n", hMenu);
4673
4674     if ((menu = MENU_GetMenu(hMenu)))
4675     {
4676         return menu->dwContextHelpID;
4677     }
4678     return 0;
4679 }
4680
4681 /**********************************************************************
4682  *         MenuItemFromPoint    (USER32.@)
4683  */
4684 INT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4685 {
4686     POPUPMENU *menu = MENU_GetMenu(hMenu);
4687     UINT pos;
4688
4689     /*FIXME: Do we have to handle hWnd here? */
4690     if (!menu) return -1;
4691     if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
4692     return pos;
4693 }
4694
4695
4696 /**********************************************************************
4697  *           translate_accelerator
4698  */
4699 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4700                                    BYTE fVirt, WORD key, WORD cmd )
4701 {
4702     INT mask = 0;
4703     UINT mesg = 0;
4704
4705     if (wParam != key) return FALSE;
4706
4707     if (GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4708     if (GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4709     if (GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4710
4711     if (message == WM_CHAR || message == WM_SYSCHAR)
4712     {
4713         if ( !(fVirt & FVIRTKEY) && (mask & FALT) == (fVirt & FALT) )
4714         {
4715             TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4716             goto found;
4717         }
4718     }
4719     else
4720     {
4721         if(fVirt & FVIRTKEY)
4722         {
4723             TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4724                           wParam, 0xff & HIWORD(lParam));
4725
4726             if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4727             TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4728         }
4729         else
4730         {
4731             if (!(lParam & 0x01000000))  /* no special_key */
4732             {
4733                 if ((fVirt & FALT) && (lParam & 0x20000000))
4734                 {                              /* ^^ ALT pressed */
4735                     TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4736                     goto found;
4737                 }
4738             }
4739         }
4740     }
4741     return FALSE;
4742
4743  found:
4744     if (message == WM_KEYUP || message == WM_SYSKEYUP)
4745         mesg = 1;
4746     else
4747     {
4748         HMENU hMenu, hSubMenu, hSysMenu;
4749         UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4750
4751         hMenu = (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4752         hSysMenu = get_win_sys_menu( hWnd );
4753
4754         /* find menu item and ask application to initialize it */
4755         /* 1. in the system menu */
4756         hSubMenu = hSysMenu;
4757         nPos = cmd;
4758         if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4759         {
4760             if (GetCapture())
4761                 mesg = 2;
4762             if (!IsWindowEnabled(hWnd))
4763                 mesg = 3;
4764             else
4765             {
4766                 SendMessageW(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4767                 if(hSubMenu != hSysMenu)
4768                 {
4769                     nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4770                     TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4771                     SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4772                 }
4773                 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4774             }
4775         }
4776         else /* 2. in the window's menu */
4777         {
4778             hSubMenu = hMenu;
4779             nPos = cmd;
4780             if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4781             {
4782                 if (GetCapture())
4783                     mesg = 2;
4784                 if (!IsWindowEnabled(hWnd))
4785                     mesg = 3;
4786                 else
4787                 {
4788                     SendMessageW(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4789                     if(hSubMenu != hMenu)
4790                     {
4791                         nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4792                         TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
4793                         SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4794                     }
4795                     uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4796                 }
4797             }
4798         }
4799
4800         if (mesg == 0)
4801         {
4802             if (uSysStat != (UINT)-1)
4803             {
4804                 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4805                     mesg=4;
4806                 else
4807                     mesg=WM_SYSCOMMAND;
4808             }
4809             else
4810             {
4811                 if (uStat != (UINT)-1)
4812                 {
4813                     if (IsIconic(hWnd))
4814                         mesg=5;
4815                     else
4816                     {
4817                         if (uStat & (MF_DISABLED|MF_GRAYED))
4818                             mesg=6;
4819                         else
4820                             mesg=WM_COMMAND;
4821                     }
4822                 }
4823                 else
4824                     mesg=WM_COMMAND;
4825             }
4826         }
4827     }
4828
4829     if( mesg==WM_COMMAND )
4830     {
4831         TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4832         SendMessageW(hWnd, mesg, 0x10000 | cmd, 0L);
4833     }
4834     else if( mesg==WM_SYSCOMMAND )
4835     {
4836         TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4837         SendMessageW(hWnd, mesg, cmd, 0x00010000L);
4838     }
4839     else
4840     {
4841         /*  some reasons for NOT sending the WM_{SYS}COMMAND message:
4842          *   #0: unknown (please report!)
4843          *   #1: for WM_KEYUP,WM_SYSKEYUP
4844          *   #2: mouse is captured
4845          *   #3: window is disabled
4846          *   #4: it's a disabled system menu option
4847          *   #5: it's a menu option, but window is iconic
4848          *   #6: it's a menu option, but disabled
4849          */
4850         TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4851         if(mesg==0)
4852             ERR_(accel)(" unknown reason - please report!\n");
4853     }
4854     return TRUE;
4855 }
4856
4857 /**********************************************************************
4858  *      TranslateAcceleratorA     (USER32.@)
4859  *      TranslateAccelerator      (USER32.@)
4860  */
4861 INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg )
4862 {
4863     /* YES, Accel16! */
4864     LPACCEL16 lpAccelTbl;
4865     int i;
4866     WPARAM wParam;
4867
4868     if (!hWnd || !msg) return 0;
4869
4870     if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
4871     {
4872         WARN_(accel)("invalid accel handle=%p\n", hAccel);
4873         return 0;
4874     }
4875
4876     wParam = msg->wParam;
4877
4878     switch (msg->message)
4879     {
4880     case WM_KEYDOWN:
4881     case WM_SYSKEYDOWN:
4882         break;
4883
4884     case WM_CHAR:
4885     case WM_SYSCHAR:
4886         {
4887             char ch = LOWORD(wParam);
4888             WCHAR wch;
4889             MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
4890             wParam = MAKEWPARAM(wch, HIWORD(wParam));
4891         }
4892         break;
4893
4894     default:
4895         return 0;
4896     }
4897
4898     TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4899                   hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4900     i = 0;
4901     do
4902     {
4903         if (translate_accelerator( hWnd, msg->message, wParam, msg->lParam,
4904                                    lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4905             return 1;
4906     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
4907
4908     return 0;
4909 }
4910
4911 /**********************************************************************
4912  *      TranslateAcceleratorW     (USER32.@)
4913  */
4914 INT WINAPI TranslateAcceleratorW( HWND hWnd, HACCEL hAccel, LPMSG msg )
4915 {
4916     /* YES, Accel16! */
4917     LPACCEL16 lpAccelTbl;
4918     int i;
4919
4920     if (!hWnd || !msg) return 0;
4921
4922     if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
4923     {
4924         WARN_(accel)("invalid accel handle=%p\n", hAccel);
4925         return 0;
4926     }
4927
4928     switch (msg->message)
4929     {
4930     case WM_KEYDOWN:
4931     case WM_SYSKEYDOWN:
4932     case WM_CHAR:
4933     case WM_SYSCHAR:
4934         break;
4935
4936     default:
4937         return 0;
4938     }
4939
4940     TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4941                   hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4942     i = 0;
4943     do
4944     {
4945         if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
4946                                    lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4947             return 1;
4948     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
4949
4950     return 0;
4951 }