Got rid of GetSysColorPen.
[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, SYSCOLOR_GetPen(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, SYSCOLOR_GetPen(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, SYSCOLOR_GetPen(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, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1549         MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1550         LineTo( hDC, lprect->right, lprect->bottom );
1551     }
1552     else 
1553     {
1554         SelectObject( hDC, SYSCOLOR_GetPen(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     if (!top_popup) top_popup = lppop->hWnd;
1669
1670     SelectObject( hdc, hMenuFont);
1671
1672       /* Clear previous highlighted item */
1673     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
1674     {
1675         lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1676         MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1677                           lppop->Height, !(lppop->wFlags & MF_POPUP),
1678                           ODA_SELECT );
1679     }
1680
1681       /* Highlight new item (if any) */
1682     lppop->FocusedItem = wIndex;
1683     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
1684     {
1685         if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1686             lppop->items[wIndex].fState |= MF_HILITE;
1687             MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc, 
1688                     &lppop->items[wIndex], lppop->Height,
1689                     !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1690         }
1691         if (sendMenuSelect)
1692         {
1693             MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1694             SendMessageA( hwndOwner, WM_MENUSELECT, 
1695                      MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1696                      ip->fType | ip->fState | MF_MOUSESELECT |
1697                      (lppop->wFlags & MF_SYSMENU)), hmenu);
1698         }
1699     }
1700     else if (sendMenuSelect) {
1701         if(topmenu){
1702             int pos;
1703             if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1704                 POPUPMENU *ptm = MENU_GetMenu( topmenu );
1705                 MENUITEM *ip = &ptm->items[pos];
1706                 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos, 
1707                          ip->fType | ip->fState | MF_MOUSESELECT |
1708                          (ptm->wFlags & MF_SYSMENU)), topmenu);
1709             }
1710         }
1711     }
1712     ReleaseDC( lppop->hWnd, hdc );
1713 }
1714
1715
1716 /***********************************************************************
1717  *           MENU_MoveSelection
1718  *
1719  * Moves currently selected item according to the offset parameter.
1720  * If there is no selection then it should select the last item if
1721  * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1722  */
1723 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1724 {
1725     INT i;
1726     POPUPMENU *menu;
1727
1728     TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1729
1730     menu = MENU_GetMenu( hmenu );
1731     if ((!menu) || (!menu->items)) return;
1732
1733     if ( menu->FocusedItem != NO_SELECTED_ITEM )
1734     {
1735         if( menu->nItems == 1 ) return; else
1736         for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems 
1737                                             ; i += offset)
1738             if (!(menu->items[i].fType & MF_SEPARATOR))
1739             {
1740                 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1741                 return;
1742             }
1743     }
1744
1745     for ( i = (offset > 0) ? 0 : menu->nItems - 1; 
1746                   i >= 0 && i < menu->nItems ; i += offset)
1747         if (!(menu->items[i].fType & MF_SEPARATOR))
1748         {
1749             MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1750             return;
1751         }
1752 }
1753
1754
1755 /**********************************************************************
1756  *         MENU_SetItemData
1757  *
1758  * Set an item flags, id and text ptr. Called by InsertMenu() and
1759  * ModifyMenu().
1760  */
1761 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1762                                 LPCWSTR str )
1763 {
1764     LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1765
1766     debug_print_menuitem("MENU_SetItemData from: ", item, "");
1767     TRACE("flags=%x str=%p\n", flags, str);
1768
1769     if (IS_STRING_ITEM(flags))
1770     {
1771         if (!str)
1772         {
1773             flags |= MF_SEPARATOR;
1774             item->text = NULL;
1775         }
1776         else
1777         {
1778             LPWSTR text;
1779             /* Item beginning with a backspace is a help item */
1780             if (*str == '\b')
1781             {
1782                 flags |= MF_HELP;
1783                 str++;
1784             }
1785             if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1786                 return FALSE;
1787             strcpyW( text, str );
1788             item->text = text;
1789         }
1790     }
1791     else if (IS_BITMAP_ITEM(flags))
1792         item->text = (LPWSTR)(HBITMAP)LOWORD(str);
1793     else item->text = NULL;
1794
1795     if (flags & MF_OWNERDRAW) 
1796         item->dwItemData = (DWORD)str;
1797     else
1798         item->dwItemData = 0;
1799
1800     if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1801         DestroyMenu( item->hSubMenu );   /* ModifyMenu() spec */
1802
1803     if (flags & MF_POPUP)
1804     {
1805         POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1806         if (menu) menu->wFlags |= MF_POPUP;
1807         else
1808         {
1809             item->wID = 0;
1810             item->hSubMenu = 0;
1811             item->fType = 0;
1812             item->fState = 0;
1813             return FALSE;
1814         }
1815     } 
1816
1817     item->wID = id;
1818     if (flags & MF_POPUP)
1819       item->hSubMenu = id;
1820
1821     if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1822       flags |= MF_POPUP; /* keep popup */
1823
1824     item->fType = flags & TYPE_MASK;
1825     item->fState = (flags & STATE_MASK) &
1826         ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1827
1828
1829     /* Don't call SetRectEmpty here! */
1830
1831
1832     if (prevText) HeapFree( GetProcessHeap(), 0, prevText );
1833
1834     debug_print_menuitem("MENU_SetItemData to  : ", item, "");
1835     return TRUE;
1836 }
1837
1838
1839 /**********************************************************************
1840  *         MENU_InsertItem
1841  *
1842  * Insert a new item into a menu.
1843  */
1844 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1845 {
1846     MENUITEM *newItems;
1847     POPUPMENU *menu;
1848
1849     if (!(menu = MENU_GetMenu(hMenu))) 
1850         return NULL;
1851
1852     /* Find where to insert new item */
1853
1854     if (flags & MF_BYPOSITION) {
1855         if (pos > menu->nItems) 
1856             pos = menu->nItems;
1857     } else {
1858         if (!MENU_FindItem( &hMenu, &pos, flags )) 
1859             pos = menu->nItems;
1860         else {
1861             if (!(menu = MENU_GetMenu( hMenu )))
1862                 return NULL;
1863         }
1864     }
1865
1866     /* Create new items array */
1867
1868     newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
1869     if (!newItems)
1870     {
1871         WARN("allocation failed\n" );
1872         return NULL;
1873     }
1874     if (menu->nItems > 0)
1875     {
1876           /* Copy the old array into the new one */
1877         if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1878         if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1879                                         (menu->nItems-pos)*sizeof(MENUITEM) );
1880         HeapFree( GetProcessHeap(), 0, menu->items );
1881     }
1882     menu->items = newItems;
1883     menu->nItems++;
1884     memset( &newItems[pos], 0, sizeof(*newItems) );
1885     menu->Height = 0; /* force size recalculate */
1886     return &newItems[pos];
1887 }
1888
1889
1890 /**********************************************************************
1891  *         MENU_ParseResource
1892  *
1893  * Parse a standard menu resource and add items to the menu.
1894  * Return a pointer to the end of the resource.
1895  */
1896 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1897 {
1898     WORD flags, id = 0;
1899     LPCSTR str;
1900
1901     do
1902     {
1903         flags = GET_WORD(res);
1904         res += sizeof(WORD);
1905         if (!(flags & MF_POPUP))
1906         {
1907             id = GET_WORD(res);
1908             res += sizeof(WORD);
1909         }
1910         if (!IS_STRING_ITEM(flags))
1911             ERR("not a string item %04x\n", flags );
1912         str = res;
1913         if (!unicode) res += strlen(str) + 1;
1914         else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1915         if (flags & MF_POPUP)
1916         {
1917             HMENU hSubMenu = CreatePopupMenu();
1918             if (!hSubMenu) return NULL;
1919             if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1920                 return NULL;
1921             if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1922             else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1923         }
1924         else  /* Not a popup */
1925         {
1926             if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1927             else AppendMenuW( hMenu, flags, id,
1928                                 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1929         }
1930     } while (!(flags & MF_END));
1931     return res;
1932 }
1933
1934
1935 /**********************************************************************
1936  *         MENUEX_ParseResource
1937  *
1938  * Parse an extended menu resource and add items to the menu.
1939  * Return a pointer to the end of the resource.
1940  */
1941 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1942 {
1943     WORD resinfo;
1944     do {
1945         MENUITEMINFOW mii;
1946
1947         mii.cbSize = sizeof(mii);
1948         mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1949         mii.fType = GET_DWORD(res);
1950         res += sizeof(DWORD);
1951         mii.fState = GET_DWORD(res);
1952         res += sizeof(DWORD);
1953         mii.wID = GET_DWORD(res);
1954         res += sizeof(DWORD);
1955         resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte.  */
1956         res += sizeof(WORD);
1957         /* Align the text on a word boundary.  */
1958         res += (~((int)res - 1)) & 1;
1959         mii.dwTypeData = (LPWSTR) res;
1960         res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
1961         /* Align the following fields on a dword boundary.  */
1962         res += (~((int)res - 1)) & 3;
1963
1964         TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1965               mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
1966
1967         if (resinfo & 1) {      /* Pop-up? */
1968             /* DWORD helpid = GET_DWORD(res); FIXME: use this.  */
1969             res += sizeof(DWORD);
1970             mii.hSubMenu = CreatePopupMenu();
1971             if (!mii.hSubMenu)
1972                 return NULL;
1973             if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
1974                 DestroyMenu(mii.hSubMenu);
1975                 return NULL;
1976             }
1977             mii.fMask |= MIIM_SUBMENU;
1978             mii.fType |= MF_POPUP;
1979         }
1980         else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
1981         {
1982             WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
1983                 mii.wID, mii.fType);
1984             mii.fType |= MF_SEPARATOR;
1985         }
1986         InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
1987     } while (!(resinfo & MF_END));
1988     return res;
1989 }
1990
1991
1992 /***********************************************************************
1993  *           MENU_GetSubPopup
1994  *
1995  * Return the handle of the selected sub-popup menu (if any).
1996  */
1997 static HMENU MENU_GetSubPopup( HMENU hmenu )
1998 {
1999     POPUPMENU *menu;
2000     MENUITEM *item;
2001
2002     menu = MENU_GetMenu( hmenu );
2003
2004     if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2005
2006     item = &menu->items[menu->FocusedItem];
2007     if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2008         return item->hSubMenu;
2009     return 0;
2010 }
2011
2012
2013 /***********************************************************************
2014  *           MENU_HideSubPopups
2015  *
2016  * Hide the sub-popup menus of this menu.
2017  */
2018 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2019                                 BOOL sendMenuSelect )
2020 {
2021     POPUPMENU *menu = MENU_GetMenu( hmenu );
2022
2023     TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2024
2025     if (menu && top_popup)
2026     {
2027         HMENU hsubmenu;
2028         POPUPMENU *submenu;
2029         MENUITEM *item;
2030
2031         if (menu->FocusedItem != NO_SELECTED_ITEM)
2032         {
2033             item = &menu->items[menu->FocusedItem];
2034             if (!(item->fType & MF_POPUP) ||
2035                 !(item->fState & MF_MOUSESELECT)) return;
2036             item->fState &= ~MF_MOUSESELECT;
2037             hsubmenu = item->hSubMenu;
2038         } else return;
2039
2040         submenu = MENU_GetMenu( hsubmenu );
2041         MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2042         MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2043         DestroyWindow( submenu->hWnd );
2044         submenu->hWnd = 0;
2045     }
2046 }
2047
2048
2049 /***********************************************************************
2050  *           MENU_ShowSubPopup
2051  *
2052  * Display the sub-menu of the selected item of this menu.
2053  * Return the handle of the submenu, or hmenu if no submenu to display.
2054  */
2055 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2056                                   BOOL selectFirst, UINT wFlags )
2057 {
2058     RECT rect;
2059     POPUPMENU *menu;
2060     MENUITEM *item;
2061     HDC hdc;
2062
2063     TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2064
2065     if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2066
2067     if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
2068
2069     item = &menu->items[menu->FocusedItem];
2070     if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
2071         return hmenu;
2072
2073     /* message must be sent before using item,
2074        because nearly everything may be changed by the application ! */
2075
2076     /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2077     if (!(wFlags & TPM_NONOTIFY))
2078        SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2079                    MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2080
2081     item = &menu->items[menu->FocusedItem];
2082     rect = item->rect;
2083
2084     /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2085     if (!(item->fState & MF_HILITE)) 
2086     {
2087         if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2088         else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2089
2090         SelectObject( hdc, hMenuFont);
2091
2092         item->fState |= MF_HILITE;
2093         MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE ); 
2094         ReleaseDC( menu->hWnd, hdc );
2095     }
2096     if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2097       item->rect = rect;
2098
2099     item->fState |= MF_MOUSESELECT;
2100
2101     if (IS_SYSTEM_MENU(menu))
2102     {
2103         MENU_InitSysMenuPopup(item->hSubMenu,
2104                               GetWindowLongA( menu->hWnd, GWL_STYLE ),
2105                               GetClassLongA( menu->hWnd, GCL_STYLE));
2106
2107         NC_GetSysPopupPos( menu->hWnd, &rect );
2108         rect.top = rect.bottom;
2109         rect.right = GetSystemMetrics(SM_CXSIZE);
2110         rect.bottom = GetSystemMetrics(SM_CYSIZE);
2111     }
2112     else
2113     {
2114         GetWindowRect( menu->hWnd, &rect );
2115         if (menu->wFlags & MF_POPUP)
2116         {
2117             rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
2118             rect.top += item->rect.top;
2119             rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2120             rect.bottom = item->rect.top - item->rect.bottom;
2121         }
2122         else
2123         {
2124             rect.left += item->rect.left;
2125             rect.top += item->rect.bottom;
2126             rect.right = item->rect.right - item->rect.left;
2127             rect.bottom = item->rect.bottom - item->rect.top;
2128         }
2129     }
2130
2131     MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2132                     rect.left, rect.top, rect.right, rect.bottom );
2133     if (selectFirst)
2134         MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2135     return item->hSubMenu;
2136 }
2137
2138
2139
2140 /**********************************************************************
2141  *         MENU_IsMenuActive
2142  */
2143 BOOL MENU_IsMenuActive(void)
2144 {
2145     return (top_popup != 0);
2146 }
2147
2148 /***********************************************************************
2149  *           MENU_PtMenu
2150  *
2151  * Walks menu chain trying to find a menu pt maps to.
2152  */
2153 static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2154 {
2155    POPUPMENU *menu = MENU_GetMenu( hMenu );
2156    UINT item = menu->FocusedItem;
2157    HMENU ret;
2158
2159    /* try subpopup first (if any) */
2160    ret = (item != NO_SELECTED_ITEM &&
2161           (menu->items[item].fType & MF_POPUP) &&
2162           (menu->items[item].fState & MF_MOUSESELECT))
2163         ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
2164
2165    if (!ret)  /* check the current window (avoiding WM_HITTEST) */
2166    {
2167        INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2168        if( menu->wFlags & MF_POPUP )
2169        {
2170            if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2171        }
2172        else if (ht == HTSYSMENU)
2173            ret = get_win_sys_menu( menu->hWnd );
2174        else if (ht == HTMENU)
2175            ret = GetMenu( menu->hWnd );
2176    }
2177    return ret;
2178 }
2179
2180 /***********************************************************************
2181  *           MENU_ExecFocusedItem
2182  *
2183  * Execute a menu item (for instance when user pressed Enter).
2184  * Return the wID of the executed item. Otherwise, -1 indicating
2185  * that no menu item was executed;
2186  * Have to receive the flags for the TrackPopupMenu options to avoid
2187  * sending unwanted message.
2188  *
2189  */
2190 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2191 {
2192     MENUITEM *item;
2193     POPUPMENU *menu = MENU_GetMenu( hMenu );
2194
2195     TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2196
2197     if (!menu || !menu->nItems || 
2198         (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2199
2200     item = &menu->items[menu->FocusedItem];
2201
2202     TRACE("%08x %08x %08x\n",
2203                  hMenu, item->wID, item->hSubMenu);
2204
2205     if (!(item->fType & MF_POPUP))
2206     {
2207         if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2208         {
2209             /* If TPM_RETURNCMD is set you return the id, but 
2210                do not send a message to the owner */       
2211             if(!(wFlags & TPM_RETURNCMD))
2212             {
2213                 if( menu->wFlags & MF_SYSMENU )
2214                     PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2215                                   MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2216                 else
2217                     PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2218             }
2219             return item->wID;
2220         }
2221     }
2222     else
2223         pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2224
2225     return -1;
2226 }
2227
2228 /***********************************************************************
2229  *           MENU_SwitchTracking
2230  *
2231  * Helper function for menu navigation routines.
2232  */
2233 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2234 {
2235     POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2236     POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2237
2238     TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2239
2240     if( pmt->hTopMenu != hPtMenu &&
2241         !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2242     {
2243         /* both are top level menus (system and menu-bar) */
2244         MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2245         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2246         pmt->hTopMenu = hPtMenu;
2247     }
2248     else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2249     MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2250 }
2251
2252
2253 /***********************************************************************
2254  *           MENU_ButtonDown
2255  *
2256  * Return TRUE if we can go on with menu tracking.
2257  */
2258 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2259 {
2260     TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2261
2262     if (hPtMenu)
2263     {
2264         UINT id = 0;
2265         POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2266         MENUITEM *item;
2267
2268         if( IS_SYSTEM_MENU(ptmenu) )
2269             item = ptmenu->items;
2270         else
2271             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2272
2273         if( item )
2274         {
2275             if( ptmenu->FocusedItem != id )
2276                 MENU_SwitchTracking( pmt, hPtMenu, id );
2277
2278             /* If the popup menu is not already "popped" */
2279             if(!(item->fState & MF_MOUSESELECT ))
2280             {
2281                 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2282
2283                 /* In win31, a newly popped menu always remains opened for the next buttonup */
2284                 if(TWEAK_WineLook == WIN31_LOOK)
2285                     ptmenu->bTimeToHide = FALSE;                    
2286             }
2287
2288             return TRUE;
2289         } 
2290         /* Else the click was on the menu bar, finish the tracking */
2291     }
2292     return FALSE;
2293 }
2294
2295 /***********************************************************************
2296  *           MENU_ButtonUp
2297  *
2298  * Return the value of MENU_ExecFocusedItem if
2299  * the selected item was not a popup. Else open the popup.
2300  * A -1 return value indicates that we go on with menu tracking.
2301  *
2302  */
2303 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2304 {
2305     TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2306
2307     if (hPtMenu)
2308     {
2309         UINT id = 0;
2310         POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2311         MENUITEM *item;
2312
2313         if( IS_SYSTEM_MENU(ptmenu) )
2314             item = ptmenu->items;
2315         else
2316             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2317
2318         if( item && (ptmenu->FocusedItem == id ))
2319         {
2320             if( !(item->fType & MF_POPUP) )
2321                 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2322
2323             /* If we are dealing with the top-level menu            */
2324             /* and this is a click on an already "popped" item:     */
2325             /* Stop the menu tracking and close the opened submenus */
2326             if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2327                 return 0;
2328         }
2329         ptmenu->bTimeToHide = TRUE;
2330     }
2331     return -1;
2332 }
2333
2334
2335 /***********************************************************************
2336  *           MENU_MouseMove
2337  *
2338  * Return TRUE if we can go on with menu tracking.
2339  */
2340 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2341 {
2342     UINT id = NO_SELECTED_ITEM;
2343     POPUPMENU *ptmenu = NULL;
2344
2345     if( hPtMenu )
2346     {
2347         ptmenu = MENU_GetMenu( hPtMenu );
2348         if( IS_SYSTEM_MENU(ptmenu) )
2349             id = 0;
2350         else
2351             MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2352     } 
2353
2354     if( id == NO_SELECTED_ITEM )
2355     {
2356         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, 
2357                          NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2358         
2359     }
2360     else if( ptmenu->FocusedItem != id )
2361     {
2362             MENU_SwitchTracking( pmt, hPtMenu, id );
2363             pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2364     }
2365     return TRUE;
2366 }
2367
2368
2369 /***********************************************************************
2370  *           MENU_DoNextMenu
2371  *
2372  * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2373  */
2374 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2375 {
2376     POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2377
2378     if( (vk == VK_LEFT &&  menu->FocusedItem == 0 ) ||
2379         (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2380     {
2381         MDINEXTMENU next_menu;
2382         HMENU hNewMenu;
2383         HWND  hNewWnd;
2384         UINT  id = 0;
2385
2386         next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2387         next_menu.hmenuNext = 0;
2388         next_menu.hwndNext = 0;
2389         SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2390
2391         TRACE("%04x [%04x] -> %04x [%04x]\n",
2392               pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2393
2394         if (!next_menu.hmenuNext || !next_menu.hwndNext)
2395         {
2396             DWORD style = GetWindowLongA( pmt->hOwnerWnd, GWL_STYLE );
2397             hNewWnd = pmt->hOwnerWnd;
2398             if( IS_SYSTEM_MENU(menu) )
2399             {
2400                 /* switch to the menu bar */
2401
2402                 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2403
2404                 if( vk == VK_LEFT )
2405                 {
2406                     menu = MENU_GetMenu( hNewMenu );
2407                     id = menu->nItems - 1;
2408                 }
2409             }
2410             else if (style & WS_SYSMENU )
2411             {
2412                 /* switch to the system menu */
2413                 hNewMenu = get_win_sys_menu( hNewWnd );
2414             }
2415             else return FALSE;
2416         }
2417         else    /* application returned a new menu to switch to */
2418         {
2419             hNewMenu = next_menu.hmenuNext;
2420             hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2421
2422             if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2423             {
2424                 DWORD style = GetWindowLongA( hNewWnd, GWL_STYLE );
2425
2426                 if (style & WS_SYSMENU &&
2427                     GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2428                 {
2429                     /* get the real system menu */
2430                     hNewMenu =  get_win_sys_menu(hNewWnd);
2431                 }
2432                 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2433                 {
2434                     /* FIXME: Not sure what to do here;
2435                      * perhaps try to track hNewMenu as a popup? */
2436
2437                     TRACE(" -- got confused.\n");
2438                     return FALSE;
2439                 }
2440             }
2441             else return FALSE;
2442         }
2443
2444         if( hNewMenu != pmt->hTopMenu )
2445         {
2446             MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, 
2447                     FALSE, 0 );
2448             if( pmt->hCurrentMenu != pmt->hTopMenu ) 
2449                 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2450         }
2451
2452         if( hNewWnd != pmt->hOwnerWnd )
2453         {
2454             ReleaseCapture(); 
2455             pmt->hOwnerWnd = hNewWnd;
2456             EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2457         }
2458
2459         pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2460         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 ); 
2461
2462         return TRUE;
2463     }
2464     return FALSE;
2465 }
2466
2467 /***********************************************************************
2468  *           MENU_SuspendPopup
2469  *
2470  * The idea is not to show the popup if the next input message is
2471  * going to hide it anyway.
2472  */
2473 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2474 {
2475     MSG msg;
2476
2477     msg.hwnd = pmt->hOwnerWnd;
2478
2479     PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2480     pmt->trackFlags |= TF_SKIPREMOVE;
2481
2482     switch( uMsg )
2483     {
2484         case WM_KEYDOWN:
2485              PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2486              if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2487              {
2488                  PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2489                  PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2490                  if( msg.message == WM_KEYDOWN &&
2491                     (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2492                  {
2493                      pmt->trackFlags |= TF_SUSPENDPOPUP;
2494                      return TRUE;
2495                  }
2496              }
2497              break;
2498     }
2499
2500     /* failures go through this */
2501     pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2502     return FALSE;
2503 }
2504
2505 /***********************************************************************
2506  *           MENU_KeyEscape
2507  *
2508  * Handle a VK_ESCAPE key event in a menu. 
2509  */
2510 static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2511 {
2512     BOOL bEndMenu = TRUE;
2513
2514     if (pmt->hCurrentMenu != pmt->hTopMenu)
2515     {
2516         POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2517
2518         if (menu->wFlags & MF_POPUP)
2519         {
2520             HMENU hmenutmp, hmenuprev;
2521
2522             hmenuprev = hmenutmp = pmt->hTopMenu;
2523
2524             /* close topmost popup */
2525             while (hmenutmp != pmt->hCurrentMenu)
2526             {
2527                 hmenuprev = hmenutmp;
2528                 hmenutmp = MENU_GetSubPopup( hmenuprev );
2529             }
2530
2531             MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2532             pmt->hCurrentMenu = hmenuprev;
2533             bEndMenu = FALSE;
2534         }
2535     }
2536
2537     return bEndMenu;
2538 }
2539
2540 /***********************************************************************
2541  *           MENU_KeyLeft
2542  *
2543  * Handle a VK_LEFT key event in a menu. 
2544  */
2545 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2546 {
2547     POPUPMENU *menu;
2548     HMENU hmenutmp, hmenuprev;
2549     UINT  prevcol;
2550
2551     hmenuprev = hmenutmp = pmt->hTopMenu;
2552     menu = MENU_GetMenu( hmenutmp );
2553
2554     /* Try to move 1 column left (if possible) */
2555     if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) != 
2556         NO_SELECTED_ITEM ) {
2557         
2558         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2559                          prevcol, TRUE, 0 );
2560         return;
2561     }
2562
2563     /* close topmost popup */
2564     while (hmenutmp != pmt->hCurrentMenu)
2565     {
2566         hmenuprev = hmenutmp;
2567         hmenutmp = MENU_GetSubPopup( hmenuprev );
2568     }
2569
2570     MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2571     pmt->hCurrentMenu = hmenuprev; 
2572
2573     if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2574     {
2575         /* move menu bar selection if no more popups are left */
2576
2577         if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2578              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2579
2580         if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2581         {
2582            /* A sublevel menu was displayed - display the next one
2583             * unless there is another displacement coming up */
2584
2585             if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2586                 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2587                                                 pmt->hTopMenu, TRUE, wFlags);
2588         }
2589     }
2590 }
2591
2592
2593 /***********************************************************************
2594  *           MENU_KeyRight
2595  *
2596  * Handle a VK_RIGHT key event in a menu.
2597  */
2598 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2599 {
2600     HMENU hmenutmp;
2601     POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2602     UINT  nextcol;
2603
2604     TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2605                   pmt->hCurrentMenu,
2606                   debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->
2607                      items[0].text),
2608                   pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2609
2610     if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2611     {
2612         /* If already displaying a popup, try to display sub-popup */
2613
2614         hmenutmp = pmt->hCurrentMenu;
2615         pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2616
2617         /* if subpopup was displayed then we are done */
2618         if (hmenutmp != pmt->hCurrentMenu) return;
2619     }
2620
2621     /* Check to see if there's another column */
2622     if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) != 
2623         NO_SELECTED_ITEM ) {
2624         TRACE("Going to %d.\n", nextcol );
2625         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2626                          nextcol, TRUE, 0 );
2627         return;
2628     }
2629
2630     if (!(menu->wFlags & MF_POPUP))     /* menu bar tracking */
2631     {
2632         if( pmt->hCurrentMenu != pmt->hTopMenu )
2633         {
2634             MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2635             hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2636         } else hmenutmp = 0;
2637
2638         /* try to move to the next item */
2639         if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2640              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2641
2642         if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2643             if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2644                 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, 
2645                                                        pmt->hTopMenu, TRUE, wFlags);
2646     }
2647 }
2648
2649 /***********************************************************************
2650  *           MENU_TrackMenu
2651  *
2652  * Menu tracking code.
2653  */
2654 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2655                               HWND hwnd, const RECT *lprect )
2656 {
2657     MSG msg;
2658     POPUPMENU *menu;
2659     BOOL fRemove;
2660     INT executedMenuId = -1;
2661     MTRACKER mt;
2662     BOOL enterIdleSent = FALSE;
2663
2664     mt.trackFlags = 0;
2665     mt.hCurrentMenu = hmenu;
2666     mt.hTopMenu = hmenu;
2667     mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2668     mt.pt.x = x;
2669     mt.pt.y = y;
2670
2671     TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2672             hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2673             (lprect) ? lprect->right : 0,  (lprect) ? lprect->bottom : 0);
2674
2675     fEndMenu = FALSE;
2676     if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2677
2678     if (wFlags & TPM_BUTTONDOWN) 
2679     {
2680         /* Get the result in order to start the tracking or not */
2681         fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2682         fEndMenu = !fRemove;   
2683     }
2684
2685     EVENT_Capture( mt.hOwnerWnd, HTMENU );
2686
2687     while (!fEndMenu)
2688     {
2689         menu = MENU_GetMenu( mt.hCurrentMenu );
2690         if (!menu) /* sometimes happens if I do a window manager close */
2691             break;
2692
2693         /* we have to keep the message in the queue until it's
2694          * clear that menu loop is not over yet. */
2695
2696         for (;;)
2697         {
2698             if (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
2699             {
2700                 if (!CallMsgFilterA( &msg, MSGF_MENU )) break;
2701                 /* remove the message from the queue */
2702                 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2703             }
2704             else
2705             {
2706                 if (!enterIdleSent)
2707                 {
2708                     HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2709                     enterIdleSent = TRUE;
2710                     SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2711                 }
2712                 WaitMessage();
2713             }
2714         }
2715
2716         /* check if EndMenu() tried to cancel us, by posting this message */
2717         if(msg.message == WM_CANCELMODE) 
2718         {
2719             /* we are now out of the loop */
2720             fEndMenu = TRUE;
2721
2722             /* remove the message from the queue */
2723             PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2724            
2725             /* break out of internal loop, ala ESCAPE */
2726             break;
2727         }
2728
2729         TranslateMessage( &msg );
2730         mt.pt = msg.pt;
2731
2732         if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2733           enterIdleSent=FALSE;
2734
2735         fRemove = FALSE;
2736         if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2737         {
2738             /* 
2739              * use the mouse coordinates in lParam instead of those in the MSG
2740              * struct to properly handle synthetic messages. lParam coords are 
2741              * relative to client area, so they must be converted; since they can
2742              * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2743              */
2744             mt.pt.x = SLOWORD(msg.lParam);
2745             mt.pt.y = SHIWORD(msg.lParam);
2746             ClientToScreen(msg.hwnd,&mt.pt);
2747
2748             /* Find a menu for this mouse event */
2749             hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2750
2751             switch(msg.message)
2752             {
2753                 /* no WM_NC... messages in captured state */
2754
2755                 case WM_RBUTTONDBLCLK:
2756                 case WM_RBUTTONDOWN:
2757                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
2758                     /* fall through */
2759                 case WM_LBUTTONDBLCLK:
2760                 case WM_LBUTTONDOWN:
2761                     /* If the message belongs to the menu, removes it from the queue */
2762                     /* Else, end menu tracking */
2763                     fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2764                     fEndMenu = !fRemove;
2765                     break;
2766                 
2767                 case WM_RBUTTONUP:
2768                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
2769                     /* fall through */
2770                 case WM_LBUTTONUP:
2771                     /* Check if a menu was selected by the mouse */
2772                     if (hmenu)
2773                     {
2774                         executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2775
2776                         /* End the loop if executedMenuId is an item ID */
2777                         /* or if the job was done (executedMenuId = 0). */
2778                         fEndMenu = fRemove = (executedMenuId != -1);
2779                     }
2780                     /* No menu was selected by the mouse */
2781                     /* if the function was called by TrackPopupMenu, continue
2782                        with the menu tracking. If not, stop it */
2783                     else
2784                         fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2785                     
2786                     break;
2787                 
2788                 case WM_MOUSEMOVE:
2789                     /* In win95 winelook, the selected menu item must be changed every time the
2790                        mouse moves. In Win31 winelook, the mouse button has to be held down */
2791                      
2792                     if ( hmenu && ((TWEAK_WineLook > WIN31_LOOK) ||
2793                          ( (msg.wParam & MK_LBUTTON) ||
2794                            ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON)))) )
2795
2796                         fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2797
2798             } /* switch(msg.message) - mouse */
2799         }
2800         else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2801         {
2802             fRemove = TRUE;  /* Keyboard messages are always removed */
2803             switch(msg.message)
2804             {
2805             case WM_KEYDOWN:
2806                 switch(msg.wParam)
2807                 {
2808                 case VK_HOME:
2809                 case VK_END:
2810                     MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, 
2811                                      NO_SELECTED_ITEM, FALSE, 0 );
2812                 /* fall through */
2813                 case VK_UP:
2814                     MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, 
2815                                        (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2816                     break;
2817
2818                 case VK_DOWN: /* If on menu bar, pull-down the menu */
2819
2820                     menu = MENU_GetMenu( mt.hCurrentMenu );
2821                     if (!(menu->wFlags & MF_POPUP))
2822                         mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2823                     else      /* otherwise try to move selection */
2824                         MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2825                     break;
2826
2827                 case VK_LEFT:
2828                     MENU_KeyLeft( &mt, wFlags );
2829                     break;
2830                     
2831                 case VK_RIGHT:
2832                     MENU_KeyRight( &mt, wFlags );
2833                     break;
2834                     
2835                 case VK_ESCAPE:
2836                     fEndMenu = MENU_KeyEscape(&mt, wFlags);
2837                     break;
2838
2839                 case VK_F1:
2840                     {
2841                         HELPINFO hi;
2842                         hi.cbSize = sizeof(HELPINFO);
2843                         hi.iContextType = HELPINFO_MENUITEM;
2844                         if (menu->FocusedItem == NO_SELECTED_ITEM) 
2845                             hi.iCtrlId = 0;
2846                         else    
2847                             hi.iCtrlId = menu->items[menu->FocusedItem].wID; 
2848                         hi.hItemHandle = hmenu;
2849                         hi.dwContextId = menu->dwContextHelpID;
2850                         hi.MousePos = msg.pt;
2851                         SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2852                         break;
2853                     }
2854
2855                 default:
2856                     break;
2857                 }
2858                 break;  /* WM_KEYDOWN */
2859
2860             case WM_SYSKEYDOWN:
2861                 switch(msg.wParam)
2862                 {
2863                 case VK_MENU:
2864                     fEndMenu = TRUE;
2865                     break;
2866                     
2867                 }
2868                 break;  /* WM_SYSKEYDOWN */
2869
2870             case WM_CHAR:
2871                 {
2872                     UINT        pos;
2873
2874                     if (msg.wParam == '\r' || msg.wParam == ' ')
2875                     {
2876                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2877                         fEndMenu = (executedMenuId != -1);
2878
2879                         break;
2880                     }
2881
2882                       /* Hack to avoid control chars. */
2883                       /* We will find a better way real soon... */
2884                     if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2885
2886                     pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu, 
2887                                               LOWORD(msg.wParam), FALSE );
2888                     if (pos == (UINT)-2) fEndMenu = TRUE;
2889                     else if (pos == (UINT)-1) MessageBeep(0);
2890                     else
2891                     {
2892                         MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2893                                 TRUE, 0 );
2894                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2895                         fEndMenu = (executedMenuId != -1);
2896                     }
2897                 }                   
2898                 break;
2899             }  /* switch(msg.message) - kbd */
2900         }
2901         else
2902         {
2903             DispatchMessageA( &msg );
2904         }
2905
2906         if (!fEndMenu) fRemove = TRUE;
2907
2908         /* finally remove message from the queue */
2909
2910         if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2911             PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2912         else mt.trackFlags &= ~TF_SKIPREMOVE;
2913     }
2914
2915     ReleaseCapture();
2916
2917     /* If dropdown is still painted and the close box is clicked on
2918        then the menu will be destroyed as part of the DispatchMessage above.
2919        This will then invalidate the menu handle in mt.hTopMenu. We should
2920        check for this first.  */
2921     if( IsMenu( mt.hTopMenu ) )
2922     {
2923         menu = MENU_GetMenu( mt.hTopMenu );
2924
2925         if( IsWindow( mt.hOwnerWnd ) )
2926         {
2927             MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2928
2929             if (menu && menu->wFlags & MF_POPUP) 
2930             {
2931                 DestroyWindow( menu->hWnd );
2932                 menu->hWnd = 0;
2933             }
2934             MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2935             SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2936         }
2937
2938         /* Reset the variable for hiding menu */
2939         if( menu ) menu->bTimeToHide = FALSE;
2940     }
2941
2942     /* The return value is only used by TrackPopupMenu */
2943     return ((executedMenuId != -1) ? executedMenuId : 0);
2944 }
2945
2946 /***********************************************************************
2947  *           MENU_InitTracking
2948  */
2949 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
2950 {
2951     TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
2952
2953     HideCaret(0);
2954
2955     /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2956     if (!(wFlags & TPM_NONOTIFY))
2957        SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2958
2959     SendMessageA( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
2960
2961     if (!(wFlags & TPM_NONOTIFY))
2962     {
2963        POPUPMENU *menu;
2964        SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
2965        if ((menu = MENU_GetMenu( hMenu )) && (!menu->Height))
2966        { /* app changed/recreated menu bar entries in WM_INITMENU
2967             Recalculate menu sizes else clicks will not work */
2968           SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2969                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2970                                                         
2971        }
2972     }
2973     return TRUE;
2974 }
2975 /***********************************************************************
2976  *           MENU_ExitTracking
2977  */
2978 static BOOL MENU_ExitTracking(HWND hWnd)
2979 {
2980     TRACE("hwnd=0x%04x\n", hWnd);
2981
2982     SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2983     ShowCaret(0);
2984     return TRUE;
2985 }
2986
2987 /***********************************************************************
2988  *           MENU_TrackMouseMenuBar
2989  *
2990  * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2991  */
2992 void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
2993 {
2994     HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
2995     UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
2996
2997     TRACE("wnd=%x ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
2998
2999     if (IsMenu(hMenu))
3000     {
3001         /* map point to parent client coordinates */
3002         HWND parent = GetAncestor( hWnd, GA_PARENT );
3003         if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );
3004
3005         MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
3006         MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
3007         MENU_ExitTracking(hWnd);
3008     }
3009 }
3010
3011
3012 /***********************************************************************
3013  *           MENU_TrackKbdMenuBar
3014  *
3015  * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3016  */
3017 void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, INT vkey)
3018 {
3019     UINT uItem = NO_SELECTED_ITEM;
3020     HMENU hTrackMenu;
3021     UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3022
3023     /* find window that has a menu */
3024
3025     while (GetWindowLongA( hwnd, GWL_STYLE ) & WS_CHILD)
3026         if (!(hwnd = GetParent( hwnd ))) return;
3027
3028     /* check if we have to track a system menu */
3029
3030     hTrackMenu = GetMenu( hwnd );
3031     if (!hTrackMenu || IsIconic(hwnd) || vkey == VK_SPACE )
3032     {
3033         if (!(GetWindowLongA( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
3034         hTrackMenu = get_win_sys_menu( hwnd );
3035         uItem = 0;
3036         wParam |= HTSYSMENU; /* prevent item lookup */
3037     }
3038
3039     if (!IsMenu( hTrackMenu )) return;
3040
3041     MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3042
3043     if( vkey && vkey != VK_SPACE )
3044     {
3045         uItem = MENU_FindItemByKey( hwnd, hTrackMenu, vkey, (wParam & HTSYSMENU) );
3046         if( uItem >= (UINT)(-2) )
3047         {
3048             if( uItem == (UINT)(-1) ) MessageBeep(0);
3049             hTrackMenu = 0;
3050         }
3051     }
3052
3053     if( hTrackMenu )
3054     {
3055         MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3056
3057         if( uItem == NO_SELECTED_ITEM )
3058             MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3059         else if( vkey )
3060             PostMessageA( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3061
3062         MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3063     }
3064     MENU_ExitTracking( hwnd );
3065 }
3066
3067
3068 /**********************************************************************
3069  *           TrackPopupMenu   (USER32.@)
3070  *
3071  * Like the win32 API, the function return the command ID only if the
3072  * flag TPM_RETURNCMD is on.
3073  *
3074  */
3075 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3076                            INT nReserved, HWND hWnd, const RECT *lpRect )
3077 {
3078     BOOL ret = FALSE;
3079
3080     MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3081
3082     /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3083     if (!(wFlags & TPM_NONOTIFY))
3084         SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3085
3086     if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3087         ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3088     MENU_ExitTracking(hWnd);
3089
3090     if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3091         ret = 1;
3092
3093     return ret;
3094 }
3095
3096 /**********************************************************************
3097  *           TrackPopupMenuEx   (USER32.@)
3098  */
3099 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3100                                 HWND hWnd, LPTPMPARAMS lpTpm )
3101 {
3102     FIXME("not fully implemented\n" );
3103     return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3104                              lpTpm ? &lpTpm->rcExclude : NULL );
3105 }
3106
3107 /***********************************************************************
3108  *           PopupMenuWndProc
3109  *
3110  * NOTE: Windows has totally different (and undocumented) popup wndproc.
3111  */
3112 static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3113 {
3114     TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3115     hwnd, message, wParam, lParam);
3116
3117     switch(message)
3118     {
3119     case WM_CREATE:
3120         {
3121             CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3122             SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3123             return 0;
3124         }
3125
3126     case WM_MOUSEACTIVATE:  /* We don't want to be activated */
3127         return MA_NOACTIVATE;
3128
3129     case WM_PAINT:
3130         {
3131             PAINTSTRUCT ps;
3132             BeginPaint( hwnd, &ps );
3133             MENU_DrawPopupMenu( hwnd, ps.hdc,
3134                                 (HMENU)GetWindowLongA( hwnd, 0 ) );
3135             EndPaint( hwnd, &ps );
3136             return 0;
3137         }
3138     case WM_ERASEBKGND:
3139         return 1;
3140
3141     case WM_DESTROY:
3142         /* zero out global pointer in case resident popup window was destroyed. */
3143         if (hwnd == top_popup) top_popup = 0;
3144         break;
3145
3146     case WM_SHOWWINDOW:
3147
3148         if( wParam )
3149         {
3150             if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
3151         }
3152         else
3153             SetWindowLongW( hwnd, 0, 0 );
3154         break;
3155
3156     case MM_SETMENUHANDLE:
3157         SetWindowLongW( hwnd, 0, wParam );
3158         break;
3159
3160     case MM_GETMENUHANDLE:
3161         return GetWindowLongW( hwnd, 0 );
3162
3163     default:
3164         return DefWindowProcW( hwnd, message, wParam, lParam );
3165     }
3166     return 0;
3167 }
3168
3169
3170 /***********************************************************************
3171  *           MENU_GetMenuBarHeight
3172  *
3173  * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3174  */
3175 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3176                               INT orgX, INT orgY )
3177 {
3178     HDC hdc;
3179     RECT rectBar;
3180     LPPOPUPMENU lppop;
3181
3182     TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3183           hwnd, menubarWidth, orgX, orgY );
3184
3185     if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3186
3187     hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3188     SelectObject( hdc, hMenuFont);       
3189     SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3190     MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );    
3191     ReleaseDC( hwnd, hdc );
3192     return lppop->Height;
3193 }
3194
3195
3196 /*******************************************************************
3197  *         ChangeMenu    (USER.153)
3198  */
3199 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3200                             UINT16 id, UINT16 flags )
3201 {
3202     TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3203                   hMenu, pos, (DWORD)data, id, flags );
3204     if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3205                                                 id, data );
3206
3207     /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3208     /* for MF_DELETE. We should check the parameters for all others */
3209     /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3210
3211     if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3212     if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3213                                                id, data );
3214     if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
3215                                               flags & MF_BYPOSITION ? pos : id,
3216                                               flags & ~MF_REMOVE );
3217     /* Default: MF_INSERT */
3218     return InsertMenu16( hMenu, pos, flags, id, data );
3219 }
3220
3221
3222 /*******************************************************************
3223  *         ChangeMenuA    (USER32.@)
3224  */
3225 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3226                              UINT id, UINT flags )
3227 {
3228     TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3229                   hMenu, pos, (DWORD)data, id, flags );
3230     if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3231                                                  id, data );
3232     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3233     if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3234                                                 id, data );
3235     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3236                                               flags & MF_BYPOSITION ? pos : id,
3237                                               flags & ~MF_REMOVE );
3238     /* Default: MF_INSERT */
3239     return InsertMenuA( hMenu, pos, flags, id, data );
3240 }
3241
3242
3243 /*******************************************************************
3244  *         ChangeMenuW    (USER32.@)
3245  */
3246 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3247                              UINT id, UINT flags )
3248 {
3249     TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3250                   hMenu, pos, (DWORD)data, id, flags );
3251     if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3252                                                  id, data );
3253     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3254     if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3255                                                 id, data );
3256     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3257                                               flags & MF_BYPOSITION ? pos : id,
3258                                               flags & ~MF_REMOVE );
3259     /* Default: MF_INSERT */
3260     return InsertMenuW( hMenu, pos, flags, id, data );
3261 }
3262
3263
3264 /*******************************************************************
3265  *         CheckMenuItem    (USER.154)
3266  */
3267 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
3268 {
3269     return (BOOL16)CheckMenuItem( hMenu, id, flags );
3270 }
3271
3272
3273 /*******************************************************************
3274  *         CheckMenuItem    (USER32.@)
3275  */
3276 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3277 {
3278     MENUITEM *item;
3279     DWORD ret;
3280
3281     TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3282     if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3283     ret = item->fState & MF_CHECKED;
3284     if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3285     else item->fState &= ~MF_CHECKED;
3286     return ret;
3287 }
3288
3289
3290 /**********************************************************************
3291  *         EnableMenuItem    (USER.155)
3292  */
3293 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3294 {
3295     return EnableMenuItem( hMenu, wItemID, wFlags );
3296 }
3297
3298
3299 /**********************************************************************
3300  *         EnableMenuItem    (USER32.@)
3301  */
3302 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3303 {
3304     UINT    oldflags;
3305     MENUITEM *item;
3306     POPUPMENU *menu;
3307
3308     TRACE("(%04x, %04X, %04X) !\n", 
3309                  hMenu, wItemID, wFlags);
3310
3311     /* Get the Popupmenu to access the owner menu */
3312     if (!(menu = MENU_GetMenu(hMenu))) 
3313         return (UINT)-1;
3314
3315     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3316         return (UINT)-1;
3317
3318     oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3319     item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3320
3321     /* In win95 if the close item in the system menu change update the close button */
3322     if (TWEAK_WineLook == WIN95_LOOK)    
3323         if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3324         {
3325             if (menu->hSysMenuOwner != 0)
3326             {
3327                 POPUPMENU* parentMenu;
3328
3329                 /* Get the parent menu to access*/
3330                 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner))) 
3331                     return (UINT)-1;
3332
3333                 /* Refresh the frame to reflect the change*/
3334                 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3335                              SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3336             }
3337         }
3338            
3339     return oldflags;
3340 }
3341
3342
3343 /*******************************************************************
3344  *         GetMenuString    (USER.161)
3345  */
3346 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3347                               LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
3348 {
3349     return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
3350 }
3351
3352
3353 /*******************************************************************
3354  *         GetMenuStringA    (USER32.@)
3355  */
3356 INT WINAPI GetMenuStringA( 
3357         HMENU hMenu,    /* [in] menuhandle */
3358         UINT wItemID,   /* [in] menu item (dep. on wFlags) */
3359         LPSTR str,      /* [out] outbuffer. If NULL, func returns entry length*/
3360         INT nMaxSiz,    /* [in] length of buffer. if 0, func returns entry len*/
3361         UINT wFlags     /* [in] MF_ flags */ 
3362 ) {
3363     MENUITEM *item;
3364
3365     TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3366                  hMenu, wItemID, str, nMaxSiz, wFlags );
3367     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3368     if (!IS_STRING_ITEM(item->fType)) return 0;
3369     if (!str || !nMaxSiz) return strlenW(item->text);
3370     str[0] = '\0';
3371     if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3372         str[nMaxSiz-1] = 0;
3373     TRACE("returning '%s'\n", str );
3374     return strlen(str);
3375 }
3376
3377
3378 /*******************************************************************
3379  *         GetMenuStringW    (USER32.@)
3380  */
3381 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3382                                LPWSTR str, INT nMaxSiz, UINT wFlags )
3383 {
3384     MENUITEM *item;
3385
3386     TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3387                  hMenu, wItemID, str, nMaxSiz, wFlags );
3388     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3389     if (!IS_STRING_ITEM(item->fType)) return 0;
3390     if (!str || !nMaxSiz) return strlenW(item->text);
3391     str[0] = '\0';
3392     lstrcpynW( str, item->text, nMaxSiz );
3393     return strlenW(str);
3394 }
3395
3396
3397 /**********************************************************************
3398  *         HiliteMenuItem    (USER32.@)
3399  */
3400 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3401                                 UINT wHilite )
3402 {
3403     LPPOPUPMENU menu;
3404     TRACE("(%04x, %04x, %04x, %04x);\n", 
3405                  hWnd, hMenu, wItemID, wHilite);
3406     if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3407     if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3408     if (menu->FocusedItem == wItemID) return TRUE;
3409     MENU_HideSubPopups( hWnd, hMenu, FALSE );
3410     MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3411     return TRUE;
3412 }
3413
3414
3415 /**********************************************************************
3416  *         GetMenuState    (USER.250)
3417  */
3418 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3419 {
3420     return GetMenuState( hMenu, wItemID, wFlags );
3421 }
3422
3423
3424 /**********************************************************************
3425  *         GetMenuState    (USER32.@)
3426  */
3427 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3428 {
3429     MENUITEM *item;
3430     TRACE("(menu=%04x, id=%04x, flags=%04x);\n", 
3431                  hMenu, wItemID, wFlags);
3432     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3433     debug_print_menuitem ("  item: ", item, "");
3434     if (item->fType & MF_POPUP)
3435     {
3436         POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3437         if (!menu) return -1;
3438         else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3439     }
3440     else
3441     {
3442         /* We used to (from way back then) mask the result to 0xff.  */
3443         /* I don't know why and it seems wrong as the documented */
3444         /* return flag MF_SEPARATOR is outside that mask.  */
3445         return (item->fType | item->fState);
3446     }
3447 }
3448
3449
3450 /**********************************************************************
3451  *         GetMenuItemCount    (USER.263)
3452  */
3453 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3454 {
3455     LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3456     if (!menu) return -1;
3457     TRACE("(%04x) returning %d\n", 
3458                   hMenu, menu->nItems );
3459     return menu->nItems;
3460 }
3461
3462
3463 /**********************************************************************
3464  *         GetMenuItemCount    (USER32.@)
3465  */
3466 INT WINAPI GetMenuItemCount( HMENU hMenu )
3467 {
3468     LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3469     if (!menu) return -1;
3470     TRACE("(%04x) returning %d\n", 
3471                   hMenu, menu->nItems );
3472     return menu->nItems;
3473 }
3474
3475 /**********************************************************************
3476  *         GetMenuItemID    (USER.264)
3477  */
3478 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3479 {
3480     return (UINT16) GetMenuItemID (hMenu, nPos);
3481 }
3482
3483 /**********************************************************************
3484  *         GetMenuItemID    (USER32.@)
3485  */
3486 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3487 {
3488     MENUITEM * lpmi;
3489
3490     if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
3491     if (lpmi->fType & MF_POPUP) return -1;
3492     return lpmi->wID;
3493
3494 }
3495
3496 /*******************************************************************
3497  *         InsertMenu    (USER.410)
3498  */
3499 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3500                             UINT16 id, SEGPTR data )
3501 {
3502     UINT pos32 = (UINT)pos;
3503     if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3504     if (IS_STRING_ITEM(flags) && data)
3505         return InsertMenuA( hMenu, pos32, flags, id, MapSL(data) );
3506     return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3507 }
3508
3509
3510 /*******************************************************************
3511  *         InsertMenuW    (USER32.@)
3512  */
3513 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3514                              UINT id, LPCWSTR str )
3515 {
3516     MENUITEM *item;
3517
3518     if (IS_STRING_ITEM(flags) && str)
3519         TRACE("hMenu %04x, pos %d, flags %08x, "
3520                       "id %04x, str %s\n",
3521                       hMenu, pos, flags, id, debugstr_w(str) );
3522     else TRACE("hMenu %04x, pos %d, flags %08x, "
3523                        "id %04x, str %08lx (not a string)\n",
3524                        hMenu, pos, flags, id, (DWORD)str );
3525
3526     if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3527
3528     if (!(MENU_SetItemData( item, flags, id, str )))
3529     {
3530         RemoveMenu( hMenu, pos, flags );
3531         return FALSE;
3532     }
3533
3534     if (flags & MF_POPUP)  /* Set the MF_POPUP flag on the popup-menu */
3535         (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3536
3537     item->hCheckBit = item->hUnCheckBit = 0;
3538     return TRUE;
3539 }
3540
3541
3542 /*******************************************************************
3543  *         InsertMenuA    (USER32.@)
3544  */
3545 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3546                              UINT id, LPCSTR str )
3547 {
3548     BOOL ret = FALSE;
3549
3550     if (IS_STRING_ITEM(flags) && str)
3551     {
3552         INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3553         LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3554         if (newstr)
3555         {
3556             MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3557             ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3558             HeapFree( GetProcessHeap(), 0, newstr );
3559         }
3560         return ret;
3561     }
3562     else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3563 }
3564
3565
3566 /*******************************************************************
3567  *         AppendMenu    (USER.411)
3568  */
3569 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3570 {
3571     return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3572 }
3573
3574
3575 /*******************************************************************
3576  *         AppendMenuA    (USER32.@)
3577  */
3578 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3579                              UINT id, LPCSTR data )
3580 {
3581     return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3582 }
3583
3584
3585 /*******************************************************************
3586  *         AppendMenuW    (USER32.@)
3587  */
3588 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3589                              UINT id, LPCWSTR data )
3590 {
3591     return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3592 }
3593
3594
3595 /**********************************************************************
3596  *         RemoveMenu   (USER.412)
3597  */
3598 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3599 {
3600     return RemoveMenu( hMenu, nPos, wFlags );
3601 }
3602
3603
3604 /**********************************************************************
3605  *         RemoveMenu    (USER32.@)
3606  */
3607 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3608 {
3609     LPPOPUPMENU menu;
3610     MENUITEM *item;
3611
3612     TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3613     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3614     if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3615     
3616       /* Remove item */
3617
3618     MENU_FreeItemData( item );
3619
3620     if (--menu->nItems == 0)
3621     {
3622         HeapFree( GetProcessHeap(), 0, menu->items );
3623         menu->items = NULL;
3624     }
3625     else
3626     {
3627         while(nPos < menu->nItems)
3628         {
3629             *item = *(item+1);
3630             item++;
3631             nPos++;
3632         }
3633         menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3634                                    menu->nItems * sizeof(MENUITEM) );
3635     }
3636     return TRUE;
3637 }
3638
3639
3640 /**********************************************************************
3641  *         DeleteMenu    (USER.413)
3642  */
3643 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3644 {
3645     return DeleteMenu( hMenu, nPos, wFlags );
3646 }
3647
3648
3649 /**********************************************************************
3650  *         DeleteMenu    (USER32.@)
3651  */
3652 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3653 {
3654     MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3655     if (!item) return FALSE;
3656     if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3657       /* nPos is now the position of the item */
3658     RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3659     return TRUE;
3660 }
3661
3662
3663 /*******************************************************************
3664  *         ModifyMenu    (USER.414)
3665  */
3666 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3667                             UINT16 id, SEGPTR data )
3668 {
3669     if (IS_STRING_ITEM(flags))
3670         return ModifyMenuA( hMenu, pos, flags, id, MapSL(data) );
3671     return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3672 }
3673
3674
3675 /*******************************************************************
3676  *         ModifyMenuW    (USER32.@)
3677  */
3678 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3679                              UINT id, LPCWSTR str )
3680 {
3681     MENUITEM *item;
3682
3683     if (IS_STRING_ITEM(flags))
3684     {
3685         TRACE("%04x %d %04x %04x %s\n",
3686                       hMenu, pos, flags, id, debugstr_w(str) );
3687         if (!str) return FALSE;
3688     }
3689     else
3690     {
3691         TRACE("%04x %d %04x %04x %08lx\n",
3692                       hMenu, pos, flags, id, (DWORD)str );
3693     }
3694
3695     if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3696     return MENU_SetItemData( item, flags, id, str );
3697 }
3698
3699
3700 /*******************************************************************
3701  *         ModifyMenuA    (USER32.@)
3702  */
3703 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3704                              UINT id, LPCSTR str )
3705 {
3706     BOOL ret = FALSE;
3707
3708     if (IS_STRING_ITEM(flags) && str)
3709     {
3710         INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3711         LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3712         if (newstr)
3713         {
3714             MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3715             ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3716             HeapFree( GetProcessHeap(), 0, newstr );
3717         }
3718         return ret;
3719     }
3720     else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3721 }
3722
3723
3724 /**********************************************************************
3725  *         CreatePopupMenu    (USER.415)
3726  */
3727 HMENU16 WINAPI CreatePopupMenu16(void)
3728 {
3729     return CreatePopupMenu();
3730 }
3731
3732
3733 /**********************************************************************
3734  *         CreatePopupMenu    (USER32.@)
3735  */
3736 HMENU WINAPI CreatePopupMenu(void)
3737 {
3738     HMENU hmenu;
3739     POPUPMENU *menu;
3740
3741     if (!(hmenu = CreateMenu())) return 0;
3742     menu = MENU_GetMenu( hmenu );
3743     menu->wFlags |= MF_POPUP;
3744     menu->bTimeToHide = FALSE;
3745     return hmenu;
3746 }
3747
3748
3749 /**********************************************************************
3750  *         GetMenuCheckMarkDimensions    (USER.417)
3751  *         GetMenuCheckMarkDimensions    (USER32.@)
3752  */
3753 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3754 {
3755     return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3756 }
3757
3758
3759 /**********************************************************************
3760  *         SetMenuItemBitmaps    (USER.418)
3761  */
3762 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3763                                     HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3764 {
3765     return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3766 }
3767
3768
3769 /**********************************************************************
3770  *         SetMenuItemBitmaps    (USER32.@)
3771  */
3772 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3773                                     HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3774 {
3775     MENUITEM *item;
3776     TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3777                  hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3778     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3779
3780     if (!hNewCheck && !hNewUnCheck)
3781     {
3782         item->fState &= ~MF_USECHECKBITMAPS;
3783     }
3784     else  /* Install new bitmaps */
3785     {
3786         item->hCheckBit = hNewCheck;
3787         item->hUnCheckBit = hNewUnCheck;
3788         item->fState |= MF_USECHECKBITMAPS;
3789     }
3790     return TRUE;
3791 }
3792
3793
3794 /**********************************************************************
3795  *         CreateMenu    (USER.151)
3796  */
3797 HMENU16 WINAPI CreateMenu16(void)
3798 {
3799     return CreateMenu();
3800 }
3801
3802
3803 /**********************************************************************
3804  *         CreateMenu    (USER32.@)
3805  */
3806 HMENU WINAPI CreateMenu(void)
3807 {
3808     HMENU hMenu;
3809     LPPOPUPMENU menu;
3810     if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3811     menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3812
3813     ZeroMemory(menu, sizeof(POPUPMENU));
3814     menu->wMagic = MENU_MAGIC;
3815     menu->FocusedItem = NO_SELECTED_ITEM;
3816     menu->bTimeToHide = FALSE;
3817
3818     TRACE("return %04x\n", hMenu );
3819
3820     return hMenu;
3821 }
3822
3823
3824 /**********************************************************************
3825  *         DestroyMenu    (USER.152)
3826  */
3827 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3828 {
3829     return DestroyMenu( hMenu );
3830 }
3831
3832
3833 /**********************************************************************
3834  *         DestroyMenu    (USER32.@)
3835  */
3836 BOOL WINAPI DestroyMenu( HMENU hMenu )
3837 {
3838     TRACE("(%04x)\n", hMenu);
3839
3840     /* Silently ignore attempts to destroy default system popup */
3841
3842     if (hMenu && hMenu != MENU_DefSysPopup)
3843     {
3844         LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3845
3846         if (!lppop) return FALSE;
3847
3848         lppop->wMagic = 0;  /* Mark it as destroyed */
3849
3850         if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
3851         {
3852             DestroyWindow( lppop->hWnd );
3853             lppop->hWnd = 0;
3854         }
3855
3856         if (lppop->items) /* recursively destroy submenus */
3857         {
3858             int i;
3859             MENUITEM *item = lppop->items;
3860             for (i = lppop->nItems; i > 0; i--, item++)
3861             {
3862                 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3863                 MENU_FreeItemData( item );
3864             }
3865             HeapFree( GetProcessHeap(), 0, lppop->items );
3866         }
3867         USER_HEAP_FREE( hMenu );
3868     }
3869     return (hMenu != MENU_DefSysPopup);
3870 }
3871
3872
3873 /**********************************************************************
3874  *         GetSystemMenu    (USER32.@)
3875  */
3876 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3877 {
3878     WND *wndPtr = WIN_FindWndPtr( hWnd );
3879     HMENU retvalue = 0;
3880
3881     if (wndPtr)
3882     {
3883         if( wndPtr->hSysMenu )
3884         {
3885             if( bRevert )
3886             {
3887                 DestroyMenu(wndPtr->hSysMenu); 
3888                 wndPtr->hSysMenu = 0;
3889             }
3890             else
3891             {
3892                 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3893                 if( menu ) 
3894                 {
3895                    if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3896                       menu->items[0].hSubMenu = MENU_CopySysPopup();
3897                 }
3898                 else 
3899                 {
3900                    WARN("Current sys-menu (%04x) of wnd %04x is broken\n", 
3901                         wndPtr->hSysMenu, hWnd);
3902                    wndPtr->hSysMenu = 0;
3903                 }
3904             }
3905         }
3906
3907         if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3908             wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3909
3910         if( wndPtr->hSysMenu )
3911         {
3912             POPUPMENU *menu;
3913             retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3914
3915             /* Store the dummy sysmenu handle to facilitate the refresh */
3916             /* of the close button if the SC_CLOSE item change */
3917             menu = MENU_GetMenu(retvalue);
3918             if ( menu )
3919                menu->hSysMenuOwner = wndPtr->hSysMenu;
3920         }
3921         WIN_ReleaseWndPtr(wndPtr);
3922     }
3923     return bRevert ? 0 : retvalue;
3924 }
3925
3926
3927 /*******************************************************************
3928  *         SetSystemMenu    (USER32.@)
3929  */
3930 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3931 {
3932     WND *wndPtr = WIN_FindWndPtr(hwnd);
3933
3934     if (wndPtr)
3935     {
3936         if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3937         wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3938         WIN_ReleaseWndPtr(wndPtr);
3939         return TRUE;
3940     }
3941     return FALSE;
3942 }
3943
3944
3945 /**********************************************************************
3946  *         GetMenu    (USER32.@)
3947  */
3948 HMENU WINAPI GetMenu( HWND hWnd ) 
3949 {
3950     HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
3951     TRACE("for %04x returning %04x\n", hWnd, retvalue);
3952     return retvalue;
3953 }
3954
3955
3956 /**********************************************************************
3957  *         SetMenu    (USER32.@)
3958  */
3959 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
3960 {
3961     TRACE("(%04x, %04x);\n", hWnd, hMenu);
3962
3963     if (hMenu && !IsMenu(hMenu))
3964     {
3965         WARN("hMenu %x is not a menu handle\n", hMenu);
3966         return FALSE;
3967     }
3968     if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
3969
3970     hWnd = WIN_GetFullHandle( hWnd );
3971     if (GetCapture() == hWnd) ReleaseCapture();
3972
3973     if (hMenu != 0)
3974     {
3975         LPPOPUPMENU lpmenu;
3976
3977         if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
3978
3979         lpmenu->hWnd = hWnd;
3980         lpmenu->Height = 0;  /* Make sure we recalculate the size */
3981     }
3982     SetWindowLongA( hWnd, GWL_ID, hMenu );
3983
3984     if (IsWindowVisible(hWnd))
3985         SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3986                       SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3987     return TRUE;
3988 }
3989
3990
3991
3992 /**********************************************************************
3993  *         GetSubMenu    (USER.159)
3994  */
3995 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
3996 {
3997     return GetSubMenu( hMenu, nPos );
3998 }
3999
4000
4001 /**********************************************************************
4002  *         GetSubMenu    (USER32.@)
4003  */
4004 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4005 {
4006     MENUITEM * lpmi;
4007
4008     if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4009     if (!(lpmi->fType & MF_POPUP)) return 0;
4010     return lpmi->hSubMenu;
4011 }
4012
4013
4014 /**********************************************************************
4015  *         DrawMenuBar    (USER32.@)
4016  */
4017 BOOL WINAPI DrawMenuBar( HWND hWnd )
4018 {
4019     LPPOPUPMENU lppop;
4020     HMENU hMenu = GetMenu(hWnd);
4021
4022     if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4023     if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4024
4025     lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4026     lppop->hwndOwner = hWnd;
4027     SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4028                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4029     return TRUE;
4030 }
4031
4032 /***********************************************************************
4033  *           DrawMenuBarTemp   (USER32.@)
4034  *
4035  * UNDOCUMENTED !!
4036  * 
4037  * called by W98SE desk.cpl Control Panel Applet
4038  *
4039  * Not 100% sure about the param names, but close.
4040  */
4041 DWORD WINAPI DrawMenuBarTemp(HWND someHWND, HDC someHDC, LPRECT someRECT, HMENU someHMENU, HFONT someFONT)
4042 {
4043     FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND, someHDC, someRECT, someHMENU, someFONT);
4044     return 0;
4045 }
4046
4047 /***********************************************************************
4048  *           EndMenu   (USER.187)
4049  *           EndMenu   (USER32.@)
4050  */
4051 void WINAPI EndMenu(void)
4052 {
4053     /* if we are in the menu code, and it is active */
4054     if (!fEndMenu && top_popup)
4055     {
4056         /* terminate the menu handling code */
4057         fEndMenu = TRUE;
4058
4059         /* needs to be posted to wakeup the internal menu handler */
4060         /* which will now terminate the menu, in the event that */
4061         /* the main window was minimized, or lost focus, so we */
4062         /* don't end up with an orphaned menu */
4063         PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
4064     }
4065 }
4066
4067
4068 /***********************************************************************
4069  *           LookupMenuHandle   (USER.217)
4070  */
4071 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4072 {
4073     HMENU hmenu32 = hmenu;
4074     UINT id32 = id;
4075     if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4076     else return hmenu32;
4077 }
4078
4079
4080 /**********************************************************************
4081  *          LoadMenu    (USER.150)
4082  */
4083 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4084 {
4085     HRSRC16 hRsrc;
4086     HGLOBAL16 handle;
4087     HMENU16 hMenu;
4088
4089     TRACE("(%04x,%s)\n", instance, debugstr_a(name) );
4090
4091     if (HIWORD(name))
4092     {
4093         if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4094     }
4095
4096     if (!name) return 0;
4097
4098     /* check for Win32 module */
4099     if (HIWORD(instance)) return LoadMenuA( instance, name );
4100     instance = GetExePtr( instance );
4101
4102     if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
4103     if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4104     hMenu = LoadMenuIndirect16(LockResource16(handle));
4105     FreeResource16( handle );
4106     return hMenu;
4107 }
4108
4109
4110 /*****************************************************************
4111  *        LoadMenuA   (USER32.@)
4112  */
4113 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4114 {
4115     HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4116     if (!hrsrc) return 0;
4117     return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4118 }
4119
4120
4121 /*****************************************************************
4122  *        LoadMenuW   (USER32.@)
4123  */
4124 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4125 {
4126     HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4127     if (!hrsrc) return 0;
4128     return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4129 }
4130
4131
4132 /**********************************************************************
4133  *          LoadMenuIndirect    (USER.220)
4134  */
4135 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4136 {
4137     HMENU16 hMenu;
4138     WORD version, offset;
4139     LPCSTR p = (LPCSTR)template;
4140
4141     TRACE("(%p)\n", template );
4142     version = GET_WORD(p);
4143     p += sizeof(WORD);
4144     if (version)
4145     {
4146         WARN("version must be 0 for Win16\n" );
4147         return 0;
4148     }
4149     offset = GET_WORD(p);
4150     p += sizeof(WORD) + offset;
4151     if (!(hMenu = CreateMenu())) return 0;
4152     if (!MENU_ParseResource( p, hMenu, FALSE ))
4153     {
4154         DestroyMenu( hMenu );
4155         return 0;
4156     }
4157     return hMenu;
4158 }
4159
4160
4161 /**********************************************************************
4162  *          LoadMenuIndirectA    (USER32.@)
4163  */
4164 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4165 {
4166     HMENU16 hMenu;
4167     WORD version, offset;
4168     LPCSTR p = (LPCSTR)template;
4169
4170     TRACE("%p\n", template );
4171     version = GET_WORD(p);
4172     p += sizeof(WORD);
4173     switch (version)
4174       {
4175       case 0:
4176         offset = GET_WORD(p);
4177         p += sizeof(WORD) + offset;
4178         if (!(hMenu = CreateMenu())) return 0;
4179         if (!MENU_ParseResource( p, hMenu, TRUE ))
4180           {
4181             DestroyMenu( hMenu );
4182             return 0;
4183           }
4184         return hMenu;
4185       case 1:
4186         offset = GET_WORD(p);
4187         p += sizeof(WORD) + offset;
4188         if (!(hMenu = CreateMenu())) return 0;
4189         if (!MENUEX_ParseResource( p, hMenu))
4190           {
4191             DestroyMenu( hMenu );
4192             return 0;
4193           }
4194         return hMenu;
4195       default:
4196         ERR("version %d not supported.\n", version);
4197         return 0;
4198       }
4199 }
4200
4201
4202 /**********************************************************************
4203  *          LoadMenuIndirectW    (USER32.@)
4204  */
4205 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4206 {
4207     /* FIXME: is there anything different between A and W? */
4208     return LoadMenuIndirectA( template );
4209 }
4210
4211
4212 /**********************************************************************
4213  *              IsMenu    (USER.358)
4214  */
4215 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
4216 {
4217     return IsMenu( hmenu );
4218 }
4219
4220
4221 /**********************************************************************
4222  *              IsMenu    (USER32.@)
4223  */
4224 BOOL WINAPI IsMenu(HMENU hmenu)
4225 {
4226     LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4227     return menu != NULL;
4228 }
4229
4230 /**********************************************************************
4231  *              GetMenuItemInfo_common
4232  */
4233
4234 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4235                                         LPMENUITEMINFOW lpmii, BOOL unicode)
4236 {
4237     MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4238
4239     debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4240
4241     if (!menu)
4242         return FALSE;
4243
4244     if (lpmii->fMask & MIIM_TYPE) {
4245         lpmii->fType = menu->fType;
4246         switch (MENU_ITEM_TYPE(menu->fType)) {
4247         case MF_STRING:
4248             break;  /* will be done below */
4249         case MF_OWNERDRAW:
4250         case MF_BITMAP:
4251             lpmii->dwTypeData = menu->text;
4252             /* fall through */
4253         default:
4254             lpmii->cch = 0;
4255         }
4256     }
4257
4258     /* copy the text string */
4259     if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4260          (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4261     {
4262         int len;
4263         if (unicode)
4264         {
4265             len = strlenW(menu->text);
4266             if(lpmii->dwTypeData && lpmii->cch)
4267                 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4268         }
4269         else
4270         {
4271             len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4272             if(lpmii->dwTypeData && lpmii->cch)
4273                 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4274                                           (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4275                     ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4276         }
4277         /* if we've copied a substring we return its length */
4278         if(lpmii->dwTypeData && lpmii->cch)
4279         {
4280             if (lpmii->cch <= len) lpmii->cch--;
4281         }
4282         else /* return length of string */
4283             lpmii->cch = len;
4284     }
4285
4286     if (lpmii->fMask & MIIM_FTYPE)
4287         lpmii->fType = menu->fType;
4288
4289     if (lpmii->fMask & MIIM_BITMAP)
4290         lpmii->hbmpItem = menu->hbmpItem;
4291
4292     if (lpmii->fMask & MIIM_STATE)
4293         lpmii->fState = menu->fState;
4294
4295     if (lpmii->fMask & MIIM_ID)
4296         lpmii->wID = menu->wID;
4297
4298     if (lpmii->fMask & MIIM_SUBMENU)
4299         lpmii->hSubMenu = menu->hSubMenu;
4300
4301     if (lpmii->fMask & MIIM_CHECKMARKS) {
4302         lpmii->hbmpChecked = menu->hCheckBit;
4303         lpmii->hbmpUnchecked = menu->hUnCheckBit;
4304     }
4305     if (lpmii->fMask & MIIM_DATA)
4306         lpmii->dwItemData = menu->dwItemData;
4307
4308   return TRUE;
4309 }
4310
4311 /**********************************************************************
4312  *              GetMenuItemInfoA    (USER32.@)
4313  */
4314 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4315                                   LPMENUITEMINFOA lpmii)
4316 {
4317     return GetMenuItemInfo_common (hmenu, item, bypos, 
4318                                     (LPMENUITEMINFOW)lpmii, FALSE);
4319 }
4320
4321 /**********************************************************************
4322  *              GetMenuItemInfoW    (USER32.@)
4323  */
4324 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4325                                   LPMENUITEMINFOW lpmii)
4326 {
4327     return GetMenuItemInfo_common (hmenu, item, bypos,
4328                                      lpmii, TRUE);
4329 }
4330
4331
4332 /* set a menu item text from a ASCII or Unicode string */
4333 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4334 {
4335     if (!text)
4336     {
4337         menu->text = NULL;
4338         menu->fType |= MF_SEPARATOR;
4339     }
4340     else if (unicode)
4341     {
4342         if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4343             strcpyW( menu->text, text );
4344     }
4345     else
4346     {
4347         LPCSTR str = (LPCSTR)text;
4348         int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4349         if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4350             MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4351     }
4352 }
4353
4354
4355 /**********************************************************************
4356  *              SetMenuItemInfo_common
4357  */
4358
4359 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4360                                        const MENUITEMINFOW *lpmii,
4361                                        BOOL unicode)
4362 {
4363     if (!menu) return FALSE;
4364
4365     debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4366
4367     if (lpmii->fMask & MIIM_TYPE ) {
4368         /* Get rid of old string.  */
4369         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4370             HeapFree(GetProcessHeap(), 0, menu->text);
4371             menu->text = NULL;
4372         }
4373
4374         /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */ 
4375         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4376         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4377
4378         menu->text = lpmii->dwTypeData;
4379
4380        if (IS_STRING_ITEM(menu->fType))
4381            set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4382     }
4383
4384     if (lpmii->fMask & MIIM_FTYPE ) {
4385         /* free the string when the type is changing */
4386         if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4387             HeapFree(GetProcessHeap(), 0, menu->text);
4388             menu->text = NULL;
4389         }
4390         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4391         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4392         if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4393             menu->fType |= MF_SEPARATOR;
4394     }
4395
4396     if (lpmii->fMask & MIIM_STRING ) {
4397         /* free the string when used */
4398         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4399             HeapFree(GetProcessHeap(), 0, menu->text);
4400             set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4401         }
4402     }
4403
4404     if (lpmii->fMask & MIIM_STATE)
4405     {
4406         /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4407         menu->fState = lpmii->fState;
4408     }
4409
4410     if (lpmii->fMask & MIIM_ID)
4411         menu->wID = lpmii->wID;
4412
4413     if (lpmii->fMask & MIIM_SUBMENU) {
4414         menu->hSubMenu = lpmii->hSubMenu;
4415         if (menu->hSubMenu) {
4416             POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4417             if (subMenu) {
4418                 subMenu->wFlags |= MF_POPUP;
4419                 menu->fType |= MF_POPUP;
4420             }
4421             else
4422                 /* FIXME: Return an error ? */
4423                 menu->fType &= ~MF_POPUP;
4424         }
4425         else
4426             menu->fType &= ~MF_POPUP;
4427     }
4428
4429     if (lpmii->fMask & MIIM_CHECKMARKS)
4430     {
4431         if (lpmii->fType & MFT_RADIOCHECK)
4432             menu->fType |= MFT_RADIOCHECK;
4433
4434         menu->hCheckBit = lpmii->hbmpChecked;
4435         menu->hUnCheckBit = lpmii->hbmpUnchecked;
4436     }
4437     if (lpmii->fMask & MIIM_DATA)
4438         menu->dwItemData = lpmii->dwItemData;
4439
4440     debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4441     return TRUE;
4442 }
4443
4444 /**********************************************************************
4445  *              SetMenuItemInfoA    (USER32.@)
4446  */
4447 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4448                                  const MENUITEMINFOA *lpmii) 
4449 {
4450     if ((lpmii->fType & (MF_HILITE|MF_POPUP)) || (lpmii->fState)) {
4451         /* QuickTime does pass invalid data into SetMenuItemInfo. 
4452          * do some of the checks Windows does.
4453          */
4454         WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4455              lpmii->fType,lpmii->fState );
4456         return FALSE;
4457     }
4458
4459     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4460                                     (const MENUITEMINFOW *)lpmii, FALSE);
4461 }
4462
4463 /**********************************************************************
4464  *              SetMenuItemInfoW    (USER32.@)
4465  */
4466 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4467                                  const MENUITEMINFOW *lpmii)
4468 {
4469     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4470                                     lpmii, TRUE);
4471 }
4472
4473 /**********************************************************************
4474  *              SetMenuDefaultItem    (USER32.@)
4475  *
4476  */
4477 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4478 {
4479         UINT i;
4480         POPUPMENU *menu;
4481         MENUITEM *item;
4482         
4483         TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4484
4485         if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4486
4487         /* reset all default-item flags */
4488         item = menu->items;
4489         for (i = 0; i < menu->nItems; i++, item++)
4490         {
4491             item->fState &= ~MFS_DEFAULT;
4492         }
4493         
4494         /* no default item */
4495         if ( -1 == uItem)
4496         {
4497             return TRUE;
4498         }
4499
4500         item = menu->items;
4501         if ( bypos )
4502         {
4503             if ( uItem >= menu->nItems ) return FALSE;
4504             item[uItem].fState |= MFS_DEFAULT;
4505             return TRUE;
4506         }
4507         else
4508         {
4509             for (i = 0; i < menu->nItems; i++, item++)
4510             {
4511                 if (item->wID == uItem)
4512                 {
4513                      item->fState |= MFS_DEFAULT;
4514                      return TRUE;
4515                 }
4516             }
4517                 
4518         }
4519         return FALSE;
4520 }
4521
4522 /**********************************************************************
4523  *              GetMenuDefaultItem    (USER32.@)
4524  */
4525 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4526 {
4527         POPUPMENU *menu;
4528         MENUITEM * item;
4529         UINT i = 0;
4530
4531         TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4532
4533         if (!(menu = MENU_GetMenu(hmenu))) return -1;
4534
4535         /* find default item */
4536         item = menu->items;
4537         
4538         /* empty menu */
4539         if (! item) return -1;
4540         
4541         while ( !( item->fState & MFS_DEFAULT ) )
4542         {
4543             i++; item++;
4544             if  (i >= menu->nItems ) return -1;
4545         }
4546         
4547         /* default: don't return disabled items */
4548         if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4549
4550         /* search rekursiv when needed */
4551         if ( (item->fType & MF_POPUP) &&  (flags & GMDI_GOINTOPOPUPS) )
4552         {
4553             UINT ret;
4554             ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4555             if ( -1 != ret ) return ret;
4556
4557             /* when item not found in submenu, return the popup item */
4558         }
4559         return ( bypos ) ? i : item->wID;
4560
4561 }
4562
4563 /*******************************************************************
4564  *              InsertMenuItem   (USER.441)
4565  *
4566  * FIXME: untested
4567  */
4568 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4569                                 const MENUITEMINFO16 *mii )
4570 {
4571     MENUITEMINFOA miia;
4572
4573     miia.cbSize        = sizeof(miia);
4574     miia.fMask         = mii->fMask;
4575     miia.dwTypeData    = (LPSTR)mii->dwTypeData;
4576     miia.fType         = mii->fType;
4577     miia.fState        = mii->fState;
4578     miia.wID           = mii->wID;
4579     miia.hSubMenu      = mii->hSubMenu;
4580     miia.hbmpChecked   = mii->hbmpChecked;
4581     miia.hbmpUnchecked = mii->hbmpUnchecked;
4582     miia.dwItemData    = mii->dwItemData;
4583     miia.cch           = mii->cch;
4584     if (IS_STRING_ITEM(miia.fType))
4585         miia.dwTypeData = MapSL(mii->dwTypeData);
4586     return InsertMenuItemA( hmenu, pos, byposition, &miia );
4587 }
4588
4589
4590 /**********************************************************************
4591  *              InsertMenuItemA    (USER32.@)
4592  */
4593 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4594                                 const MENUITEMINFOA *lpmii)
4595 {
4596     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4597     return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4598 }
4599
4600
4601 /**********************************************************************
4602  *              InsertMenuItemW    (USER32.@)
4603  */
4604 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4605                                 const MENUITEMINFOW *lpmii)
4606 {
4607     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4608     return SetMenuItemInfo_common(item, lpmii, TRUE);
4609 }
4610
4611 /**********************************************************************
4612  *              CheckMenuRadioItem    (USER32.@)
4613  */
4614
4615 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4616                                    UINT first, UINT last, UINT check,
4617                                    UINT bypos)
4618 {
4619      MENUITEM *mifirst, *milast, *micheck;
4620      HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4621
4622      TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4623                   hMenu, first, last, check, bypos);
4624
4625      mifirst = MENU_FindItem (&mfirst, &first, bypos);
4626      milast = MENU_FindItem (&mlast, &last, bypos);
4627      micheck = MENU_FindItem (&mcheck, &check, bypos);
4628
4629      if (mifirst == NULL || milast == NULL || micheck == NULL ||
4630          mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4631          micheck > milast || micheck < mifirst)
4632           return FALSE;
4633
4634      while (mifirst <= milast)
4635      {
4636           if (mifirst == micheck)
4637           {
4638                mifirst->fType |= MFT_RADIOCHECK;
4639                mifirst->fState |= MFS_CHECKED;
4640           } else {
4641                mifirst->fType &= ~MFT_RADIOCHECK;
4642                mifirst->fState &= ~MFS_CHECKED;
4643           }
4644           mifirst++;
4645      }
4646
4647      return TRUE;
4648 }
4649
4650 /**********************************************************************
4651  *              CheckMenuRadioItem (USER.666)
4652  */
4653 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4654                                    UINT16 first, UINT16 last, UINT16 check,
4655                                    BOOL16 bypos)
4656 {
4657      return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4658 }
4659
4660 /**********************************************************************
4661  *              GetMenuItemRect    (USER32.@)
4662  *
4663  *      ATTENTION: Here, the returned values in rect are the screen 
4664  *                 coordinates of the item just like if the menu was 
4665  *                 always on the upper left side of the application.
4666  *                 
4667  */
4668 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4669                                  LPRECT rect)
4670 {
4671      POPUPMENU *itemMenu;
4672      MENUITEM *item;
4673      HWND referenceHwnd;
4674
4675      TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4676
4677      item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4678      referenceHwnd = hwnd;
4679
4680      if(!hwnd)
4681      {
4682          itemMenu = MENU_GetMenu(hMenu);
4683          if (itemMenu == NULL) 
4684              return FALSE;
4685
4686          if(itemMenu->hWnd == 0)
4687              return FALSE;
4688          referenceHwnd = itemMenu->hWnd;
4689      }
4690
4691      if ((rect == NULL) || (item == NULL)) 
4692          return FALSE;
4693
4694      *rect = item->rect;
4695
4696      MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4697
4698      return TRUE;
4699 }
4700
4701
4702 /**********************************************************************
4703  *              SetMenuInfo    (USER32.@)
4704  *
4705  * FIXME
4706  *      MIM_APPLYTOSUBMENUS
4707  *      actually use the items to draw the menu
4708  */
4709 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4710 {
4711     POPUPMENU *menu;
4712
4713     TRACE("(0x%04x %p)\n", hMenu, lpmi);
4714
4715     if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4716     {
4717
4718         if (lpmi->fMask & MIM_BACKGROUND)
4719             menu->hbrBack = lpmi->hbrBack;
4720
4721         if (lpmi->fMask & MIM_HELPID)
4722             menu->dwContextHelpID = lpmi->dwContextHelpID;
4723
4724         if (lpmi->fMask & MIM_MAXHEIGHT)
4725             menu->cyMax = lpmi->cyMax;
4726
4727         if (lpmi->fMask & MIM_MENUDATA)
4728             menu->dwMenuData = lpmi->dwMenuData;
4729
4730         if (lpmi->fMask & MIM_STYLE)
4731             menu->dwStyle = lpmi->dwStyle;
4732
4733         return TRUE;
4734     }
4735     return FALSE;
4736 }
4737
4738 /**********************************************************************
4739  *              GetMenuInfo    (USER32.@)
4740  *
4741  *  NOTES
4742  *      win98/NT5.0
4743  *
4744  */
4745 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4746 {   POPUPMENU *menu;
4747
4748     TRACE("(0x%04x %p)\n", hMenu, lpmi);
4749
4750     if (lpmi && (menu = MENU_GetMenu(hMenu)))
4751     {
4752
4753         if (lpmi->fMask & MIM_BACKGROUND)
4754             lpmi->hbrBack = menu->hbrBack;
4755
4756         if (lpmi->fMask & MIM_HELPID)
4757             lpmi->dwContextHelpID = menu->dwContextHelpID;
4758
4759         if (lpmi->fMask & MIM_MAXHEIGHT)
4760             lpmi->cyMax = menu->cyMax;
4761
4762         if (lpmi->fMask & MIM_MENUDATA)
4763             lpmi->dwMenuData = menu->dwMenuData;
4764
4765         if (lpmi->fMask & MIM_STYLE)
4766             lpmi->dwStyle = menu->dwStyle;
4767
4768         return TRUE;
4769     }
4770     return FALSE;
4771 }
4772
4773 /**********************************************************************
4774  *         SetMenuContextHelpId    (USER.384)
4775  */
4776 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4777 {
4778         return SetMenuContextHelpId( hMenu, dwContextHelpID );
4779 }
4780
4781
4782 /**********************************************************************
4783  *         SetMenuContextHelpId    (USER32.@)
4784  */
4785 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4786 {
4787     LPPOPUPMENU menu;
4788
4789     TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4790
4791     if ((menu = MENU_GetMenu(hMenu)))
4792     {
4793         menu->dwContextHelpID = dwContextHelpID;
4794         return TRUE;
4795     }
4796     return FALSE;
4797 }
4798
4799 /**********************************************************************
4800  *         GetMenuContextHelpId    (USER.385)
4801  */
4802 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4803 {
4804         return GetMenuContextHelpId( hMenu );
4805 }
4806  
4807 /**********************************************************************
4808  *         GetMenuContextHelpId    (USER32.@)
4809  */
4810 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4811 {
4812     LPPOPUPMENU menu;
4813
4814     TRACE("(0x%04x)\n", hMenu);
4815
4816     if ((menu = MENU_GetMenu(hMenu)))
4817     {
4818         return menu->dwContextHelpID;
4819     }
4820     return 0;
4821 }
4822
4823 /**********************************************************************
4824  *         MenuItemFromPoint    (USER32.@)
4825  */
4826 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4827 {
4828     POPUPMENU *menu = MENU_GetMenu(hMenu);
4829     UINT pos;
4830     MENUITEM *item;
4831
4832     /*FIXME: Do we have to handle hWnd here? */
4833     item = MENU_FindItemByCoords(menu, ptScreen, &pos);
4834
4835     return pos;
4836 }
4837
4838
4839 /**********************************************************************
4840  *           translate_accelerator
4841  */
4842 static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4843                                    BYTE fVirt, WORD key, WORD cmd )
4844 {
4845     UINT mesg = 0;
4846
4847     if (wParam != key) return FALSE;
4848
4849     if (message == WM_CHAR)
4850     {
4851         if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
4852         {
4853             TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4854             goto found;
4855         }
4856     }
4857     else
4858     {
4859         if(fVirt & FVIRTKEY)
4860         {
4861             INT mask = 0;
4862             TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4863                           wParam, 0xff & HIWORD(lParam));
4864             if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4865             if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4866             if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4867             if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4868             TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4869         }
4870         else
4871         {
4872             if (!(lParam & 0x01000000))  /* no special_key */
4873             {
4874                 if ((fVirt & FALT) && (lParam & 0x20000000))
4875                 {                              /* ^^ ALT pressed */
4876                     TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4877                     goto found;
4878                 }
4879             }
4880         }
4881     }
4882     return FALSE;
4883
4884  found:
4885     if (message == WM_KEYUP || message == WM_SYSKEYUP)
4886         mesg = 1;
4887     else if (GetCapture())
4888         mesg = 2;
4889     else if (!IsWindowEnabled(hWnd))
4890         mesg = 3;
4891     else
4892     {
4893         HMENU hMenu, hSubMenu, hSysMenu;
4894         UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4895
4896         hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4897         hSysMenu = get_win_sys_menu( hWnd );
4898
4899         /* find menu item and ask application to initialize it */
4900         /* 1. in the system menu */
4901         hSubMenu = hSysMenu;
4902         nPos = cmd;
4903         if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4904         {
4905             SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4906             if(hSubMenu != hSysMenu)
4907             {
4908                 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4909                 TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4910                 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4911             }
4912             uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4913         }
4914         else /* 2. in the window's menu */
4915         {
4916             hSubMenu = hMenu;
4917             nPos = cmd;
4918             if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4919             {
4920                 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4921                 if(hSubMenu != hMenu)
4922                 {
4923                     nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4924                     TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
4925                     SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4926                 }
4927                 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4928             }
4929         }
4930
4931         if (uSysStat != (UINT)-1)
4932         {
4933             if (uSysStat & (MF_DISABLED|MF_GRAYED))
4934                 mesg=4;
4935             else
4936                 mesg=WM_SYSCOMMAND;
4937         }
4938         else
4939         {
4940             if (uStat != (UINT)-1)
4941             {
4942                 if (IsIconic(hWnd))
4943                     mesg=5;
4944                 else
4945                 {
4946                     if (uStat & (MF_DISABLED|MF_GRAYED))
4947                         mesg=6;
4948                     else
4949                         mesg=WM_COMMAND;
4950                 }
4951             }
4952             else
4953                 mesg=WM_COMMAND;
4954         }
4955     }
4956
4957     if( mesg==WM_COMMAND )
4958     {
4959         TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4960         SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
4961     }
4962     else if( mesg==WM_SYSCOMMAND )
4963     {
4964         TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4965         SendMessageA(hWnd, mesg, cmd, 0x00010000L);
4966     }
4967     else
4968     {
4969         /*  some reasons for NOT sending the WM_{SYS}COMMAND message: 
4970          *   #0: unknown (please report!)
4971          *   #1: for WM_KEYUP,WM_SYSKEYUP
4972          *   #2: mouse is captured
4973          *   #3: window is disabled 
4974          *   #4: it's a disabled system menu option
4975          *   #5: it's a menu option, but window is iconic
4976          *   #6: it's a menu option, but disabled
4977          */
4978         TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4979         if(mesg==0)
4980             ERR_(accel)(" unknown reason - please report!");
4981     }
4982     return TRUE;
4983 }
4984
4985 /**********************************************************************
4986  *      TranslateAccelerator      (USER32.@)
4987  *      TranslateAcceleratorA     (USER32.@)
4988  *      TranslateAcceleratorW     (USER32.@)
4989  */
4990 INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
4991 {
4992     /* YES, Accel16! */
4993     LPACCEL16 lpAccelTbl;
4994     int i;
4995
4996     if (msg == NULL)
4997     {
4998         WARN_(accel)("msg null; should hang here to be win compatible\n");
4999         return 0;
5000     }
5001     if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(hAccel)))
5002     {
5003         WARN_(accel)("invalid accel handle=%x\n", hAccel);
5004         return 0;
5005     }
5006     if ((msg->message != WM_KEYDOWN &&
5007          msg->message != WM_KEYUP &&
5008          msg->message != WM_SYSKEYDOWN &&
5009          msg->message != WM_SYSKEYUP &&
5010          msg->message != WM_CHAR)) return 0;
5011
5012     TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5013                   "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5014                   hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5015
5016     i = 0;
5017     do
5018     {
5019         if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5020                                    lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5021             return 1;
5022     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5023     WARN_(accel)("couldn't translate accelerator key\n");
5024     return 0;
5025 }