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