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