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