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