Fixed, added or implemented stubs:
[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  * UNDOCUMENTED !!
3983  * 
3984  * called by W98SE desk.cpl Control Panel Applet
3985  *
3986  * Not 100% sure about the param names, but close.
3987  */
3988 DWORD WINAPI DrawMenuBarTemp(HWND someHWND, HDC someHDC, LPRECT someRECT, HMENU someHMENU, HFONT someFONT)
3989 {
3990     FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND, someHDC, someRECT, someHMENU, someFONT);
3991     return 0;
3992 }
3993
3994 /***********************************************************************
3995  *           EndMenu   (USER.187)
3996  *           EndMenu   (USER32.@)
3997  */
3998 void WINAPI EndMenu(void)
3999 {
4000     /* if we are in the menu code, and it is active */
4001     if (!fEndMenu && top_popup)
4002     {
4003         /* terminate the menu handling code */
4004         fEndMenu = TRUE;
4005
4006         /* needs to be posted to wakeup the internal menu handler */
4007         /* which will now terminate the menu, in the event that */
4008         /* the main window was minimized, or lost focus, so we */
4009         /* don't end up with an orphaned menu */
4010         PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
4011     }
4012 }
4013
4014
4015 /***********************************************************************
4016  *           LookupMenuHandle   (USER.217)
4017  */
4018 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4019 {
4020     HMENU hmenu32 = hmenu;
4021     UINT id32 = id;
4022     if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4023     else return hmenu32;
4024 }
4025
4026
4027 /**********************************************************************
4028  *          LoadMenu    (USER.150)
4029  */
4030 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4031 {
4032     HRSRC16 hRsrc;
4033     HGLOBAL16 handle;
4034     HMENU16 hMenu;
4035
4036     TRACE("(%04x,%s)\n", instance, debugres_a(name) );
4037
4038     if (HIWORD(name))
4039     {
4040         if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4041     }
4042
4043     if (!name) return 0;
4044
4045     /* check for Win32 module */
4046     if (HIWORD(instance)) return LoadMenuA( instance, name );
4047     instance = GetExePtr( instance );
4048
4049     if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
4050     if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4051     hMenu = LoadMenuIndirect16(LockResource16(handle));
4052     FreeResource16( handle );
4053     return hMenu;
4054 }
4055
4056
4057 /*****************************************************************
4058  *        LoadMenuA   (USER32.@)
4059  */
4060 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4061 {
4062     HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4063     if (!hrsrc) return 0;
4064     return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4065 }
4066
4067
4068 /*****************************************************************
4069  *        LoadMenuW   (USER32.@)
4070  */
4071 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4072 {
4073     HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4074     if (!hrsrc) return 0;
4075     return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4076 }
4077
4078
4079 /**********************************************************************
4080  *          LoadMenuIndirect    (USER.220)
4081  */
4082 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4083 {
4084     HMENU16 hMenu;
4085     WORD version, offset;
4086     LPCSTR p = (LPCSTR)template;
4087
4088     TRACE("(%p)\n", template );
4089     version = GET_WORD(p);
4090     p += sizeof(WORD);
4091     if (version)
4092     {
4093         WARN("version must be 0 for Win16\n" );
4094         return 0;
4095     }
4096     offset = GET_WORD(p);
4097     p += sizeof(WORD) + offset;
4098     if (!(hMenu = CreateMenu())) return 0;
4099     if (!MENU_ParseResource( p, hMenu, FALSE ))
4100     {
4101         DestroyMenu( hMenu );
4102         return 0;
4103     }
4104     return hMenu;
4105 }
4106
4107
4108 /**********************************************************************
4109  *          LoadMenuIndirectA    (USER32.@)
4110  */
4111 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4112 {
4113     HMENU16 hMenu;
4114     WORD version, offset;
4115     LPCSTR p = (LPCSTR)template;
4116
4117     TRACE("%p\n", template );
4118     version = GET_WORD(p);
4119     p += sizeof(WORD);
4120     switch (version)
4121       {
4122       case 0:
4123         offset = GET_WORD(p);
4124         p += sizeof(WORD) + offset;
4125         if (!(hMenu = CreateMenu())) return 0;
4126         if (!MENU_ParseResource( p, hMenu, TRUE ))
4127           {
4128             DestroyMenu( hMenu );
4129             return 0;
4130           }
4131         return hMenu;
4132       case 1:
4133         offset = GET_WORD(p);
4134         p += sizeof(WORD) + offset;
4135         if (!(hMenu = CreateMenu())) return 0;
4136         if (!MENUEX_ParseResource( p, hMenu))
4137           {
4138             DestroyMenu( hMenu );
4139             return 0;
4140           }
4141         return hMenu;
4142       default:
4143         ERR("version %d not supported.\n", version);
4144         return 0;
4145       }
4146 }
4147
4148
4149 /**********************************************************************
4150  *          LoadMenuIndirectW    (USER32.@)
4151  */
4152 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4153 {
4154     /* FIXME: is there anything different between A and W? */
4155     return LoadMenuIndirectA( template );
4156 }
4157
4158
4159 /**********************************************************************
4160  *              IsMenu    (USER.358)
4161  */
4162 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4163 {
4164     return IsMenu( hmenu );
4165 }
4166
4167
4168 /**********************************************************************
4169  *              IsMenu    (USER32.@)
4170  */
4171 BOOL WINAPI IsMenu(HMENU hmenu)
4172 {
4173     LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4174     return menu != NULL;
4175 }
4176
4177 /**********************************************************************
4178  *              GetMenuItemInfo_common
4179  */
4180
4181 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4182                                         LPMENUITEMINFOW lpmii, BOOL unicode)
4183 {
4184     MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4185
4186     debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4187
4188     if (!menu)
4189         return FALSE;
4190
4191     if (lpmii->fMask & MIIM_TYPE) {
4192         lpmii->fType = menu->fType;
4193         switch (MENU_ITEM_TYPE(menu->fType)) {
4194         case MF_STRING:
4195             break;  /* will be done below */
4196         case MF_OWNERDRAW:
4197         case MF_BITMAP:
4198             lpmii->dwTypeData = menu->text;
4199             /* fall through */
4200         default:
4201             lpmii->cch = 0;
4202         }
4203     }
4204
4205     /* copy the text string */
4206     if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4207          (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4208     {
4209         int len;
4210         if (unicode)
4211         {
4212             len = strlenW(menu->text);
4213             if(lpmii->dwTypeData && lpmii->cch)
4214                 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4215         }
4216         else
4217         {
4218             len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4219             if(lpmii->dwTypeData && lpmii->cch)
4220                 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4221                                           (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4222                     ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4223         }
4224         /* if we've copied a substring we return its length */
4225         if(lpmii->dwTypeData && lpmii->cch)
4226         {
4227             if (lpmii->cch <= len) lpmii->cch--;
4228         }
4229         else /* return length of string */
4230             lpmii->cch = len;
4231     }
4232
4233     if (lpmii->fMask & MIIM_FTYPE)
4234         lpmii->fType = menu->fType;
4235
4236     if (lpmii->fMask & MIIM_BITMAP)
4237         lpmii->hbmpItem = menu->hbmpItem;
4238
4239     if (lpmii->fMask & MIIM_STATE)
4240         lpmii->fState = menu->fState;
4241
4242     if (lpmii->fMask & MIIM_ID)
4243         lpmii->wID = menu->wID;
4244
4245     if (lpmii->fMask & MIIM_SUBMENU)
4246         lpmii->hSubMenu = menu->hSubMenu;
4247
4248     if (lpmii->fMask & MIIM_CHECKMARKS) {
4249         lpmii->hbmpChecked = menu->hCheckBit;
4250         lpmii->hbmpUnchecked = menu->hUnCheckBit;
4251     }
4252     if (lpmii->fMask & MIIM_DATA)
4253         lpmii->dwItemData = menu->dwItemData;
4254
4255   return TRUE;
4256 }
4257
4258 /**********************************************************************
4259  *              GetMenuItemInfoA    (USER32.@)
4260  */
4261 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4262                                   LPMENUITEMINFOA lpmii)
4263 {
4264     return GetMenuItemInfo_common (hmenu, item, bypos, 
4265                                     (LPMENUITEMINFOW)lpmii, FALSE);
4266 }
4267
4268 /**********************************************************************
4269  *              GetMenuItemInfoW    (USER32.@)
4270  */
4271 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4272                                   LPMENUITEMINFOW lpmii)
4273 {
4274     return GetMenuItemInfo_common (hmenu, item, bypos,
4275                                      lpmii, TRUE);
4276 }
4277
4278
4279 /* set a menu item text from a ASCII or Unicode string */
4280 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4281 {
4282     if (!text)
4283     {
4284         menu->text = NULL;
4285         menu->fType |= MF_SEPARATOR;
4286     }
4287     else if (unicode)
4288     {
4289         if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4290             strcpyW( menu->text, text );
4291     }
4292     else
4293     {
4294         LPCSTR str = (LPCSTR)text;
4295         int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4296         if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4297             MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4298     }
4299 }
4300
4301
4302 /**********************************************************************
4303  *              SetMenuItemInfo_common
4304  */
4305
4306 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4307                                        const MENUITEMINFOW *lpmii,
4308                                        BOOL unicode)
4309 {
4310     if (!menu) return FALSE;
4311
4312     debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4313
4314     if (lpmii->fMask & MIIM_TYPE ) {
4315         /* Get rid of old string.  */
4316         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4317             HeapFree(GetProcessHeap(), 0, menu->text);
4318             menu->text = NULL;
4319         }
4320
4321         /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */ 
4322         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4323         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4324
4325         menu->text = lpmii->dwTypeData;
4326
4327        if (IS_STRING_ITEM(menu->fType))
4328            set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4329     }
4330
4331     if (lpmii->fMask & MIIM_FTYPE ) {
4332         /* free the string when the type is changing */
4333         if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4334             HeapFree(GetProcessHeap(), 0, menu->text);
4335             menu->text = NULL;
4336         }
4337         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4338         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4339         if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4340             menu->fType |= MF_SEPARATOR;
4341     }
4342
4343     if (lpmii->fMask & MIIM_STRING ) {
4344         /* free the string when used */
4345         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4346             HeapFree(GetProcessHeap(), 0, menu->text);
4347             set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4348         }
4349     }
4350
4351     if (lpmii->fMask & MIIM_STATE)
4352     {
4353         /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4354         menu->fState = lpmii->fState;
4355     }
4356
4357     if (lpmii->fMask & MIIM_ID)
4358         menu->wID = lpmii->wID;
4359
4360     if (lpmii->fMask & MIIM_SUBMENU) {
4361         menu->hSubMenu = lpmii->hSubMenu;
4362         if (menu->hSubMenu) {
4363             POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4364             if (subMenu) {
4365                 subMenu->wFlags |= MF_POPUP;
4366                 menu->fType |= MF_POPUP;
4367             }
4368             else
4369                 /* FIXME: Return an error ? */
4370                 menu->fType &= ~MF_POPUP;
4371         }
4372         else
4373             menu->fType &= ~MF_POPUP;
4374     }
4375
4376     if (lpmii->fMask & MIIM_CHECKMARKS)
4377     {
4378         if (lpmii->fType & MFT_RADIOCHECK)
4379             menu->fType |= MFT_RADIOCHECK;
4380
4381         menu->hCheckBit = lpmii->hbmpChecked;
4382         menu->hUnCheckBit = lpmii->hbmpUnchecked;
4383     }
4384     if (lpmii->fMask & MIIM_DATA)
4385         menu->dwItemData = lpmii->dwItemData;
4386
4387     debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4388     return TRUE;
4389 }
4390
4391 /**********************************************************************
4392  *              SetMenuItemInfoA    (USER32.@)
4393  */
4394 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4395                                  const MENUITEMINFOA *lpmii) 
4396 {
4397     if ((lpmii->fType & (MF_HILITE|MF_POPUP)) || (lpmii->fState)) {
4398         /* QuickTime does pass invalid data into SetMenuItemInfo. 
4399          * do some of the checks Windows does.
4400          */
4401         WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4402              lpmii->fType,lpmii->fState );
4403         return FALSE;
4404     }
4405
4406     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4407                                     (const MENUITEMINFOW *)lpmii, FALSE);
4408 }
4409
4410 /**********************************************************************
4411  *              SetMenuItemInfoW    (USER32.@)
4412  */
4413 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4414                                  const MENUITEMINFOW *lpmii)
4415 {
4416     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4417                                     lpmii, TRUE);
4418 }
4419
4420 /**********************************************************************
4421  *              SetMenuDefaultItem    (USER32.@)
4422  *
4423  */
4424 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4425 {
4426         UINT i;
4427         POPUPMENU *menu;
4428         MENUITEM *item;
4429         
4430         TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4431
4432         if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4433
4434         /* reset all default-item flags */
4435         item = menu->items;
4436         for (i = 0; i < menu->nItems; i++, item++)
4437         {
4438             item->fState &= ~MFS_DEFAULT;
4439         }
4440         
4441         /* no default item */
4442         if ( -1 == uItem)
4443         {
4444             return TRUE;
4445         }
4446
4447         item = menu->items;
4448         if ( bypos )
4449         {
4450             if ( uItem >= menu->nItems ) return FALSE;
4451             item[uItem].fState |= MFS_DEFAULT;
4452             return TRUE;
4453         }
4454         else
4455         {
4456             for (i = 0; i < menu->nItems; i++, item++)
4457             {
4458                 if (item->wID == uItem)
4459                 {
4460                      item->fState |= MFS_DEFAULT;
4461                      return TRUE;
4462                 }
4463             }
4464                 
4465         }
4466         return FALSE;
4467 }
4468
4469 /**********************************************************************
4470  *              GetMenuDefaultItem    (USER32.@)
4471  */
4472 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4473 {
4474         POPUPMENU *menu;
4475         MENUITEM * item;
4476         UINT i = 0;
4477
4478         TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4479
4480         if (!(menu = MENU_GetMenu(hmenu))) return -1;
4481
4482         /* find default item */
4483         item = menu->items;
4484         
4485         /* empty menu */
4486         if (! item) return -1;
4487         
4488         while ( !( item->fState & MFS_DEFAULT ) )
4489         {
4490             i++; item++;
4491             if  (i >= menu->nItems ) return -1;
4492         }
4493         
4494         /* default: don't return disabled items */
4495         if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4496
4497         /* search rekursiv when needed */
4498         if ( (item->fType & MF_POPUP) &&  (flags & GMDI_GOINTOPOPUPS) )
4499         {
4500             UINT ret;
4501             ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4502             if ( -1 != ret ) return ret;
4503
4504             /* when item not found in submenu, return the popup item */
4505         }
4506         return ( bypos ) ? i : item->wID;
4507
4508 }
4509
4510 /*******************************************************************
4511  *              InsertMenuItem   (USER.441)
4512  *
4513  * FIXME: untested
4514  */
4515 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4516                                 const MENUITEMINFO16 *mii )
4517 {
4518     MENUITEMINFOA miia;
4519
4520     miia.cbSize        = sizeof(miia);
4521     miia.fMask         = mii->fMask;
4522     miia.dwTypeData    = (LPSTR)mii->dwTypeData;
4523     miia.fType         = mii->fType;
4524     miia.fState        = mii->fState;
4525     miia.wID           = mii->wID;
4526     miia.hSubMenu      = mii->hSubMenu;
4527     miia.hbmpChecked   = mii->hbmpChecked;
4528     miia.hbmpUnchecked = mii->hbmpUnchecked;
4529     miia.dwItemData    = mii->dwItemData;
4530     miia.cch           = mii->cch;
4531     if (IS_STRING_ITEM(miia.fType))
4532         miia.dwTypeData = MapSL(mii->dwTypeData);
4533     return InsertMenuItemA( hmenu, pos, byposition, &miia );
4534 }
4535
4536
4537 /**********************************************************************
4538  *              InsertMenuItemA    (USER32.@)
4539  */
4540 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4541                                 const MENUITEMINFOA *lpmii)
4542 {
4543     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4544     return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4545 }
4546
4547
4548 /**********************************************************************
4549  *              InsertMenuItemW    (USER32.@)
4550  */
4551 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4552                                 const MENUITEMINFOW *lpmii)
4553 {
4554     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4555     return SetMenuItemInfo_common(item, lpmii, TRUE);
4556 }
4557
4558 /**********************************************************************
4559  *              CheckMenuRadioItem    (USER32.@)
4560  */
4561
4562 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4563                                    UINT first, UINT last, UINT check,
4564                                    UINT bypos)
4565 {
4566      MENUITEM *mifirst, *milast, *micheck;
4567      HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4568
4569      TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4570                   hMenu, first, last, check, bypos);
4571
4572      mifirst = MENU_FindItem (&mfirst, &first, bypos);
4573      milast = MENU_FindItem (&mlast, &last, bypos);
4574      micheck = MENU_FindItem (&mcheck, &check, bypos);
4575
4576      if (mifirst == NULL || milast == NULL || micheck == NULL ||
4577          mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4578          micheck > milast || micheck < mifirst)
4579           return FALSE;
4580
4581      while (mifirst <= milast)
4582      {
4583           if (mifirst == micheck)
4584           {
4585                mifirst->fType |= MFT_RADIOCHECK;
4586                mifirst->fState |= MFS_CHECKED;
4587           } else {
4588                mifirst->fType &= ~MFT_RADIOCHECK;
4589                mifirst->fState &= ~MFS_CHECKED;
4590           }
4591           mifirst++;
4592      }
4593
4594      return TRUE;
4595 }
4596
4597 /**********************************************************************
4598  *              CheckMenuRadioItem (USER.666)
4599  */
4600 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4601                                    UINT16 first, UINT16 last, UINT16 check,
4602                                    BOOL16 bypos)
4603 {
4604      return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4605 }
4606
4607 /**********************************************************************
4608  *              GetMenuItemRect    (USER32.@)
4609  *
4610  *      ATTENTION: Here, the returned values in rect are the screen 
4611  *                 coordinates of the item just like if the menu was 
4612  *                 always on the upper left side of the application.
4613  *                 
4614  */
4615 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4616                                  LPRECT rect)
4617 {
4618      POPUPMENU *itemMenu;
4619      MENUITEM *item;
4620      HWND referenceHwnd;
4621
4622      TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4623
4624      item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4625      referenceHwnd = hwnd;
4626
4627      if(!hwnd)
4628      {
4629          itemMenu = MENU_GetMenu(hMenu);
4630          if (itemMenu == NULL) 
4631              return FALSE;
4632
4633          if(itemMenu->hWnd == 0)
4634              return FALSE;
4635          referenceHwnd = itemMenu->hWnd;
4636      }
4637
4638      if ((rect == NULL) || (item == NULL)) 
4639          return FALSE;
4640
4641      *rect = item->rect;
4642
4643      MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4644
4645      return TRUE;
4646 }
4647
4648
4649 /**********************************************************************
4650  *              SetMenuInfo    (USER32.@)
4651  *
4652  * FIXME
4653  *      MIM_APPLYTOSUBMENUS
4654  *      actually use the items to draw the menu
4655  */
4656 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4657 {
4658     POPUPMENU *menu;
4659
4660     TRACE("(0x%04x %p)\n", hMenu, lpmi);
4661
4662     if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4663     {
4664
4665         if (lpmi->fMask & MIM_BACKGROUND)
4666             menu->hbrBack = lpmi->hbrBack;
4667
4668         if (lpmi->fMask & MIM_HELPID)
4669             menu->dwContextHelpID = lpmi->dwContextHelpID;
4670
4671         if (lpmi->fMask & MIM_MAXHEIGHT)
4672             menu->cyMax = lpmi->cyMax;
4673
4674         if (lpmi->fMask & MIM_MENUDATA)
4675             menu->dwMenuData = lpmi->dwMenuData;
4676
4677         if (lpmi->fMask & MIM_STYLE)
4678             menu->dwStyle = lpmi->dwStyle;
4679
4680         return TRUE;
4681     }
4682     return FALSE;
4683 }
4684
4685 /**********************************************************************
4686  *              GetMenuInfo    (USER32.@)
4687  *
4688  *  NOTES
4689  *      win98/NT5.0
4690  *
4691  */
4692 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4693 {   POPUPMENU *menu;
4694
4695     TRACE("(0x%04x %p)\n", hMenu, lpmi);
4696
4697     if (lpmi && (menu = MENU_GetMenu(hMenu)))
4698     {
4699
4700         if (lpmi->fMask & MIM_BACKGROUND)
4701             lpmi->hbrBack = menu->hbrBack;
4702
4703         if (lpmi->fMask & MIM_HELPID)
4704             lpmi->dwContextHelpID = menu->dwContextHelpID;
4705
4706         if (lpmi->fMask & MIM_MAXHEIGHT)
4707             lpmi->cyMax = menu->cyMax;
4708
4709         if (lpmi->fMask & MIM_MENUDATA)
4710             lpmi->dwMenuData = menu->dwMenuData;
4711
4712         if (lpmi->fMask & MIM_STYLE)
4713             lpmi->dwStyle = menu->dwStyle;
4714
4715         return TRUE;
4716     }
4717     return FALSE;
4718 }
4719
4720 /**********************************************************************
4721  *         SetMenuContextHelpId    (USER.384)
4722  */
4723 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4724 {
4725         return SetMenuContextHelpId( hMenu, dwContextHelpID );
4726 }
4727
4728
4729 /**********************************************************************
4730  *         SetMenuContextHelpId    (USER32.@)
4731  */
4732 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4733 {
4734     LPPOPUPMENU menu;
4735
4736     TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4737
4738     if ((menu = MENU_GetMenu(hMenu)))
4739     {
4740         menu->dwContextHelpID = dwContextHelpID;
4741         return TRUE;
4742     }
4743     return FALSE;
4744 }
4745
4746 /**********************************************************************
4747  *         GetMenuContextHelpId    (USER.385)
4748  */
4749 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4750 {
4751         return GetMenuContextHelpId( hMenu );
4752 }
4753  
4754 /**********************************************************************
4755  *         GetMenuContextHelpId    (USER32.@)
4756  */
4757 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4758 {
4759     LPPOPUPMENU menu;
4760
4761     TRACE("(0x%04x)\n", hMenu);
4762
4763     if ((menu = MENU_GetMenu(hMenu)))
4764     {
4765         return menu->dwContextHelpID;
4766     }
4767     return 0;
4768 }
4769
4770 /**********************************************************************
4771  *         MenuItemFromPoint    (USER32.@)
4772  */
4773 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4774 {
4775     FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n", 
4776           hWnd, hMenu, ptScreen.x, ptScreen.y);
4777     return 0;
4778 }
4779
4780
4781 /**********************************************************************
4782  *           translate_accelerator
4783  */
4784 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4785                                    BYTE fVirt, WORD key, WORD cmd )
4786 {
4787     UINT mesg = 0;
4788
4789     if (wParam != key) return FALSE;
4790
4791     if (message == WM_CHAR)
4792     {
4793         if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
4794         {
4795             TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4796             goto found;
4797         }
4798     }
4799     else
4800     {
4801         if(fVirt & FVIRTKEY)
4802         {
4803             INT mask = 0;
4804             TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4805                           wParam, 0xff & HIWORD(lParam));
4806             if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4807             if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4808             if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4809             if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4810             TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4811         }
4812         else
4813         {
4814             if (!(lParam & 0x01000000))  /* no special_key */
4815             {
4816                 if ((fVirt & FALT) && (lParam & 0x20000000))
4817                 {                              /* ^^ ALT pressed */
4818                     TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4819                     goto found;
4820                 }
4821             }
4822         }
4823     }
4824     return FALSE;
4825
4826  found:
4827     if (message == WM_KEYUP || message == WM_SYSKEYUP)
4828         mesg = 1;
4829     else if (GetCapture())
4830         mesg = 2;
4831     else if (!IsWindowEnabled(hWnd))
4832         mesg = 3;
4833     else
4834     {
4835         HMENU hMenu, hSubMenu, hSysMenu;
4836         UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4837
4838         hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4839         hSysMenu = get_win_sys_menu( hWnd );
4840
4841         /* find menu item and ask application to initialize it */
4842         /* 1. in the system menu */
4843         hSubMenu = hSysMenu;
4844         nPos = cmd;
4845         if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4846         {
4847             SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4848             if(hSubMenu != hSysMenu)
4849             {
4850                 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4851                 TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4852                 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4853             }
4854             uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4855         }
4856         else /* 2. in the window's menu */
4857         {
4858             hSubMenu = hMenu;
4859             nPos = cmd;
4860             if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4861             {
4862                 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4863                 if(hSubMenu != hMenu)
4864                 {
4865                     nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4866                     TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
4867                     SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4868                 }
4869                 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4870             }
4871         }
4872
4873         if (uSysStat != (UINT)-1)
4874         {
4875             if (uSysStat & (MF_DISABLED|MF_GRAYED))
4876                 mesg=4;
4877             else
4878                 mesg=WM_SYSCOMMAND;
4879         }
4880         else
4881         {
4882             if (uStat != (UINT)-1)
4883             {
4884                 if (IsIconic(hWnd))
4885                     mesg=5;
4886                 else
4887                 {
4888                     if (uStat & (MF_DISABLED|MF_GRAYED))
4889                         mesg=6;
4890                     else
4891                         mesg=WM_COMMAND;
4892                 }
4893             }
4894             else
4895                 mesg=WM_COMMAND;
4896         }
4897     }
4898
4899     if( mesg==WM_COMMAND )
4900     {
4901         TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4902         SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
4903     }
4904     else if( mesg==WM_SYSCOMMAND )
4905     {
4906         TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4907         SendMessageA(hWnd, mesg, cmd, 0x00010000L);
4908     }
4909     else
4910     {
4911         /*  some reasons for NOT sending the WM_{SYS}COMMAND message: 
4912          *   #0: unknown (please report!)
4913          *   #1: for WM_KEYUP,WM_SYSKEYUP
4914          *   #2: mouse is captured
4915          *   #3: window is disabled 
4916          *   #4: it's a disabled system menu option
4917          *   #5: it's a menu option, but window is iconic
4918          *   #6: it's a menu option, but disabled
4919          */
4920         TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4921         if(mesg==0)
4922             ERR_(accel)(" unknown reason - please report!");
4923     }
4924     return TRUE;
4925 }
4926
4927 /**********************************************************************
4928  *      TranslateAccelerator      (USER32.@)
4929  *      TranslateAcceleratorA     (USER32.@)
4930  *      TranslateAcceleratorW     (USER32.@)
4931  */
4932 INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
4933 {
4934     /* YES, Accel16! */
4935     LPACCEL16 lpAccelTbl;
4936     int i;
4937
4938     if (msg == NULL)
4939     {
4940         WARN_(accel)("msg null; should hang here to be win compatible\n");
4941         return 0;
4942     }
4943     if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(hAccel)))
4944     {
4945         WARN_(accel)("invalid accel handle=%x\n", hAccel);
4946         return 0;
4947     }
4948     if ((msg->message != WM_KEYDOWN &&
4949          msg->message != WM_KEYUP &&
4950          msg->message != WM_SYSKEYDOWN &&
4951          msg->message != WM_SYSKEYUP &&
4952          msg->message != WM_CHAR)) return 0;
4953
4954     TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
4955                   "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
4956                   hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4957
4958     i = 0;
4959     do
4960     {
4961         if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
4962                                    lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4963             return 1;
4964     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
4965     WARN_(accel)("couldn't translate accelerator key\n");
4966     return 0;
4967 }