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