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