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