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