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