Fixed a lot of warnings using WINE_UNUSED, casts, commenting out and
[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 "win.h"
21 #include "wine/winbase16.h"
22 #include "wine/winuser16.h"
23 #include "sysmetrics.h"
24 #include "task.h"
25 #include "heap.h"
26 #include "menu.h"
27 #include "nonclient.h"
28 #include "user.h"
29 #include "message.h"
30 #include "resource.h"
31 #include "tweak.h"
32
33 #include "debug.h"
34
35
36 /* internal popup menu window messages */
37
38 #define MM_SETMENUHANDLE        (WM_USER + 0)
39 #define MM_GETMENUHANDLE        (WM_USER + 1)
40
41 /* Menu item structure */
42 typedef struct {
43     /* ----------- MENUITEMINFO Stuff ----------- */
44     UINT fType;         /* Item type. */
45     UINT fState;                /* Item state.  */
46     UINT wID;                   /* Item id.  */
47     HMENU hSubMenu;             /* Pop-up menu.  */
48     HBITMAP hCheckBit;  /* Bitmap when checked.  */
49     HBITMAP hUnCheckBit;        /* Bitmap when unchecked.  */
50     LPSTR text;                 /* Item text or bitmap handle.  */
51     DWORD dwItemData;           /* Application defined.  */
52     /* ----------- Wine stuff ----------- */
53     RECT      rect;          /* Item area (relative to menu window) */
54     UINT      xTab;          /* X position of text after Tab */
55 } MENUITEM;
56
57 /* Popup menu structure */
58 typedef struct {
59     WORD        wFlags;       /* Menu flags (MF_POPUP, MF_SYSMENU) */
60     WORD        wMagic;       /* Magic number */
61     HQUEUE16    hTaskQ;       /* Task queue for this menu */
62     WORD        Width;        /* Width of the whole menu */
63     WORD        Height;       /* Height of the whole menu */
64     WORD        nItems;       /* Number of items in the menu */
65     HWND      hWnd;         /* Window containing the menu */
66     MENUITEM   *items;        /* Array of menu items */
67     UINT      FocusedItem;  /* Currently focused item */
68     WORD        defitem;      /* default item position. Unused (except for set/get)*/
69 } POPUPMENU, *LPPOPUPMENU;
70
71 /* internal flags for menu tracking */
72
73 #define TF_ENDMENU              0x0001
74 #define TF_SUSPENDPOPUP         0x0002
75 #define TF_SKIPREMOVE           0x0004
76
77 typedef struct
78 {
79     UINT        trackFlags;
80     HMENU       hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
81     HMENU       hTopMenu;     /* initial menu */
82     HWND        hOwnerWnd;    /* where notifications are sent */
83     POINT       pt;
84 } MTRACKER;
85
86 #define MENU_MAGIC   0x554d  /* 'MU' */
87 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
88
89 #define ITEM_PREV               -1
90 #define ITEM_NEXT                1
91
92   /* Internal MENU_TrackMenu() flags */
93 #define TPM_INTERNAL            0xF0000000
94 #define TPM_ENTERIDLEEX         0x80000000              /* set owner window for WM_ENTERIDLE */
95 #define TPM_BUTTONDOWN          0x40000000              /* menu was clicked before tracking */
96 #define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
97
98   /* popup menu shade thickness */
99 #define POPUP_XSHADE            4
100 #define POPUP_YSHADE            4
101
102   /* Space between 2 menu bar items */
103 #define MENU_BAR_ITEMS_SPACE 12
104
105   /* Minimum width of a tab character */
106 #define MENU_TAB_SPACE 8
107
108   /* Height of a separator item */
109 #define SEPARATOR_HEIGHT 5
110
111   /* (other menu->FocusedItem values give the position of the focused item) */
112 #define NO_SELECTED_ITEM  0xffff
113
114 #define MENU_ITEM_TYPE(flags) \
115   ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
116
117 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
118
119 #define IS_SYSTEM_MENU(menu)  \
120         (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
121 #define IS_SYSTEM_POPUP(menu) \
122         ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
123
124 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
125                    MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
126                    MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
127                    MF_POPUP | MF_SYSMENU | MF_HELP)
128 #define STATE_MASK (~TYPE_MASK)
129
130   /* Dimension of the menu bitmaps */
131 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
132 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
133
134 static HBITMAP hStdRadioCheck = 0;
135 static HBITMAP hStdCheck = 0;
136 static HBITMAP hStdMnArrow = 0;
137
138 // Minimze/restore/close buttons to be inserted in menubar
139 static HBITMAP hBmpMinimize = 0;
140 static HBITMAP hBmpMinimizeD = 0;
141 static HBITMAP hBmpMaximize = 0;
142 static HBITMAP hBmpMaximizeD = 0;
143 static HBITMAP hBmpClose = 0;
144 static HBITMAP hBmpCloseD = 0;
145
146
147 static HBRUSH hShadeBrush = 0;
148 static HMENU MENU_DefSysPopup = 0;  /* Default system menu popup */
149
150 /* Use global popup window because there's no way 2 menus can
151  * be tracked at the same time.  */ 
152
153 static WND* pTopPopupWnd   = 0;
154 static UINT uSubPWndLevel = 0;
155
156   /* Flag set by EndMenu() to force an exit from menu tracking */
157 static BOOL fEndMenu = FALSE;
158
159
160 /***********************************************************************
161  *           debug_print_menuitem
162  *
163  * Print a menuitem in readable form.
164  */
165
166 #define debug_print_menuitem(pre, mp, post) \
167   if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
168
169 #define MENUOUT(text) \
170   dsprintf(menu, "%s%s", (count++ ? "," : ""), (text))
171
172 #define MENUFLAG(bit,text) \
173   do { \
174     if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
175   } while (0)
176
177 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp, 
178                                     const char *postfix)
179 {
180     dbg_decl_str(menu, 256);
181
182     if (mp) {
183         UINT flags = mp->fType;
184         int typ = MENU_ITEM_TYPE(flags);
185         dsprintf(menu, "{ ID=0x%x", mp->wID);
186         if (flags & MF_POPUP)
187             dsprintf(menu, ", Sub=0x%x", mp->hSubMenu);
188         if (flags) {
189             int count = 0;
190             dsprintf(menu, ", Typ=");
191             if (typ == MFT_STRING)
192                 /* Nothing */ ;
193             else if (typ == MFT_SEPARATOR)
194                 MENUOUT("sep");
195             else if (typ == MFT_OWNERDRAW)
196                 MENUOUT("own");
197             else if (typ == MFT_BITMAP)
198                 MENUOUT("bit");
199             else
200                 MENUOUT("???");
201             flags -= typ;
202
203             MENUFLAG(MF_POPUP, "pop");
204             MENUFLAG(MFT_MENUBARBREAK, "barbrk");
205             MENUFLAG(MFT_MENUBREAK, "brk");
206             MENUFLAG(MFT_RADIOCHECK, "radio");
207             MENUFLAG(MFT_RIGHTORDER, "rorder");
208             MENUFLAG(MF_SYSMENU, "sys");
209             MENUFLAG(MFT_RIGHTJUSTIFY, "right");
210
211             if (flags)
212                 dsprintf(menu, "+0x%x", flags);
213         }
214         flags = mp->fState;
215         if (flags) {
216             int count = 0;
217             dsprintf(menu, ", State=");
218             MENUFLAG(MFS_GRAYED, "grey");
219             MENUFLAG(MFS_DISABLED, "dis");
220             MENUFLAG(MFS_CHECKED, "check");
221             MENUFLAG(MFS_HILITE, "hi");
222             MENUFLAG(MF_USECHECKBITMAPS, "usebit");
223             MENUFLAG(MF_MOUSESELECT, "mouse");
224             if (flags)
225                 dsprintf(menu, "+0x%x", flags);
226         }
227         if (mp->hCheckBit)
228             dsprintf(menu, ", Chk=0x%x", mp->hCheckBit);
229         if (mp->hUnCheckBit)
230             dsprintf(menu, ", Unc=0x%x", mp->hUnCheckBit);
231
232         if (typ == MFT_STRING) {
233             if (mp->text)
234                 dsprintf(menu, ", Text=\"%s\"", mp->text);
235             else
236                 dsprintf(menu, ", Text=Null");
237         } else if (mp->text == NULL)
238             /* Nothing */ ;
239         else
240             dsprintf(menu, ", Text=%p", mp->text);
241         dsprintf(menu, " }");
242     } else {
243         dsprintf(menu, "NULL");
244     }
245
246     TRACE(menu, "%s %s %s\n", prefix, dbg_str(menu), postfix);
247 }
248
249 #undef MENUOUT
250 #undef MENUFLAG
251
252 /***********************************************************************
253  *           MENU_CopySysPopup
254  *
255  * Return the default system menu.
256  */
257 static HMENU MENU_CopySysPopup(void)
258 {
259     HMENU hMenu = LoadMenuIndirectA(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU));
260
261     if( hMenu ) {
262         POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
263         menu->wFlags |= MF_SYSMENU | MF_POPUP;
264     }
265     else {
266         hMenu = 0;
267         ERR(menu, "Unable to load default system menu\n" );
268     }
269
270     TRACE(menu, "returning %x.\n", hMenu );
271
272     return hMenu;
273 }
274
275
276 /**********************************************************************
277  *           MENU_GetSysMenu
278  *
279  * Create a copy of the system menu. System menu in Windows is
280  * a special menu-bar with the single entry - system menu popup.
281  * This popup is presented to the outside world as a "system menu". 
282  * However, the real system menu handle is sometimes seen in the 
283  * WM_MENUSELECT paramemters (and Word 6 likes it this way).
284  */
285 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
286 {
287     HMENU hMenu;
288
289     if ((hMenu = CreateMenu()))
290     {
291         POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
292         menu->wFlags = MF_SYSMENU;
293         menu->hWnd = hWnd;
294
295         if (hPopupMenu == (HMENU)(-1))
296             hPopupMenu = MENU_CopySysPopup();
297         else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup; 
298
299         if (hPopupMenu)
300         {
301             InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
302
303             menu->items[0].fType = MF_SYSMENU | MF_POPUP;
304             menu->items[0].fState = 0;
305             menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
306             menu->wFlags |= MF_SYSMENU;
307
308             TRACE(menu,"GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
309             return hMenu;
310         }
311         DestroyMenu( hMenu );
312     }
313     ERR(menu, "failed to load system menu!\n");
314     return 0;
315 }
316
317
318 /***********************************************************************
319  *           MENU_Init
320  *
321  * Menus initialisation.
322  */
323 BOOL MENU_Init()
324 {
325     HBITMAP hBitmap;
326     static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
327                                             0x55, 0, 0xAA, 0,
328                                             0x55, 0, 0xAA, 0,
329                                             0x55, 0, 0xAA, 0 };
330
331     /* Load menu bitmaps */
332     hStdCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK));
333     hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK));
334     hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
335     /* Load system buttons bitmaps */
336     hBmpMinimize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE));
337     hBmpMinimizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED));
338     hBmpMaximize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE));
339     hBmpMaximizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED));
340     hBmpClose = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE));
341     hBmpCloseD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED));
342
343     if (hStdCheck)
344     {
345         BITMAP bm;
346         GetObjectA( hStdCheck, sizeof(bm), &bm );
347         check_bitmap_width = bm.bmWidth;
348         check_bitmap_height = bm.bmHeight;
349     } else
350          return FALSE;
351
352     /* Assume that radio checks have the same size as regular check.  */
353     if (!hStdRadioCheck)
354          return FALSE;
355
356     if (hStdMnArrow)
357         {
358          BITMAP bm;
359             GetObjectA( hStdMnArrow, sizeof(bm), &bm );
360             arrow_bitmap_width = bm.bmWidth;
361             arrow_bitmap_height = bm.bmHeight;
362     } else
363          return FALSE;
364
365     if ((hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
366             {
367                 if((hShadeBrush = CreatePatternBrush( hBitmap )))
368                 {
369                     DeleteObject( hBitmap );
370               if ((MENU_DefSysPopup = MENU_CopySysPopup()))
371                    return TRUE;
372         }
373     }
374
375     return FALSE;
376 }
377
378 /***********************************************************************
379  *           MENU_InitSysMenuPopup
380  *
381  * Grey the appropriate items in System menu.
382  */
383 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
384 {
385     BOOL gray;
386
387     gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
388     EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
389     gray = ((style & WS_MAXIMIZE) != 0);
390     EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
391     gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
392     EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
393     gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
394     EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
395     gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
396     EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
397     gray = (clsStyle & CS_NOCLOSE) != 0;
398     EnableMenuItem( hmenu, SC_CLOSE, (gray ? MF_GRAYED : MF_ENABLED) );
399 }
400
401
402 /******************************************************************************
403  *
404  *   UINT32  MENU_GetStartOfNextColumn(
405  *     HMENU32  hMenu )
406  *
407  *****************************************************************************/
408
409 static UINT  MENU_GetStartOfNextColumn(
410     HMENU  hMenu )
411 {
412     POPUPMENU  *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
413     UINT  i = menu->FocusedItem + 1;
414
415     if(!menu)
416         return NO_SELECTED_ITEM;
417
418     if( i == NO_SELECTED_ITEM )
419         return i;
420
421     for( ; i < menu->nItems; ++i ) {
422         if (menu->items[i].fType & MF_MENUBARBREAK)
423             return i;
424     }
425
426     return NO_SELECTED_ITEM;
427 }
428
429
430 /******************************************************************************
431  *
432  *   UINT32  MENU_GetStartOfPrevColumn(
433  *     HMENU32  hMenu )
434  *
435  *****************************************************************************/
436
437 static UINT  MENU_GetStartOfPrevColumn(
438     HMENU  hMenu )
439 {
440     POPUPMENU const  *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
441     UINT  i;
442
443     if( !menu )
444         return NO_SELECTED_ITEM;
445
446     if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
447         return NO_SELECTED_ITEM;
448
449     /* Find the start of the column */
450
451     for(i = menu->FocusedItem; i != 0 &&
452          !(menu->items[i].fType & MF_MENUBARBREAK);
453         --i); /* empty */
454
455     if(i == 0)
456         return NO_SELECTED_ITEM;
457
458     for(--i; i != 0; --i) {
459         if (menu->items[i].fType & MF_MENUBARBREAK)
460             break;
461     }
462
463     TRACE(menu, "ret %d.\n", i );
464
465     return i;
466 }
467
468
469
470 /***********************************************************************
471  *           MENU_FindItem
472  *
473  * Find a menu item. Return a pointer on the item, and modifies *hmenu
474  * in case the item was in a sub-menu.
475  */
476 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
477 {
478     POPUPMENU *menu;
479     UINT i;
480
481     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu))) return NULL;
482     if (wFlags & MF_BYPOSITION)
483     {
484         if (*nPos >= menu->nItems) return NULL;
485         return &menu->items[*nPos];
486     }
487     else
488     {
489         MENUITEM *item = menu->items;
490         for (i = 0; i < menu->nItems; i++, item++)
491         {
492             if (item->wID == *nPos)
493             {
494                 *nPos = i;
495                 return item;
496             }
497             else if (item->fType & MF_POPUP)
498             {
499                 HMENU hsubmenu = item->hSubMenu;
500                 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
501                 if (subitem)
502                 {
503                     *hmenu = hsubmenu;
504                     return subitem;
505                 }
506             }
507         }
508     }
509     return NULL;
510 }
511
512 /***********************************************************************
513  *           MENU_FreeItemData
514  */
515 static void MENU_FreeItemData( MENUITEM* item )
516 {
517     /* delete text */
518     if (IS_STRING_ITEM(item->fType) && item->text)
519         HeapFree( SystemHeap, 0, item->text );
520 }
521
522 /***********************************************************************
523  *           MENU_FindItemByCoords
524  *
525  * Find the item at the specified coordinates (screen coords). Does 
526  * not work for child windows and therefore should not be called for 
527  * an arbitrary system menu.
528  */
529 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, 
530                                         POINT pt, UINT *pos )
531 {
532     MENUITEM *item;
533     WND *wndPtr;
534     UINT i;
535
536     if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
537     pt.x -= wndPtr->rectWindow.left;
538     pt.y -= wndPtr->rectWindow.top;
539     item = menu->items;
540     for (i = 0; i < menu->nItems; i++, item++)
541     {
542         if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
543             (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
544         {
545             if (pos) *pos = i;
546             return item;
547         }
548     }
549     return NULL;
550 }
551
552
553 /***********************************************************************
554  *           MENU_FindItemByKey
555  *
556  * Find the menu item selected by a key press.
557  * Return item id, -1 if none, -2 if we should close the menu.
558  */
559 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, 
560                                   UINT key, BOOL forceMenuChar )
561 {
562     TRACE(menu,"\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
563
564     if (!IsMenu( hmenu )) 
565     {
566         WND* w = WIN_FindWndPtr(hwndOwner);
567         hmenu = GetSubMenu(w->hSysMenu, 0);
568     }
569
570     if (hmenu)
571     {
572         POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
573         MENUITEM *item = menu->items;
574         LONG menuchar;
575
576         if( !forceMenuChar )
577         {
578              UINT i;
579
580              key = toupper(key);
581              for (i = 0; i < menu->nItems; i++, item++)
582              {
583                 if (item->text && (IS_STRING_ITEM(item->fType)))
584                 {
585                     char *p = item->text - 2;
586                     do
587                     {
588                         p = strchr (p + 2, '&');
589                     }
590                     while (p != NULL && p [1] == '&');
591                     if (p && (toupper(p[1]) == key)) return i;
592                 }
593              }
594         }
595         menuchar = SendMessageA( hwndOwner, WM_MENUCHAR, 
596                                    MAKEWPARAM( key, menu->wFlags ), hmenu );
597         if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
598         if (HIWORD(menuchar) == 1) return (UINT)(-2);
599     }
600     return (UINT)(-1);
601 }
602 /***********************************************************************
603  *           MENU_LoadMagicItem
604  *
605  * Load the bitmap associated with the magic menu item and its style
606  */
607
608 static HBITMAP MENU_LoadMagicItem(UINT id,BOOL hilite)
609 {
610     // Magic menu item id's section
611     // These magic id's are used by windows to insert "standard" mdi
612     // buttons (minimize,restore,close) on menu. Under windows,
613     // these magic id's make sure the right things appear when those
614     // bitmap buttons are pressed/selected/released.
615
616     switch(id)
617     {
618     case MAGIC_REDUCE   : return (hilite ? hBmpMinimizeD : hBmpMinimize);
619     case MAGIC_RESTORE  : return (hilite ? hBmpMaximizeD: hBmpMaximize);
620     case MAGIC_CLOSE    : return (hilite ? hBmpCloseD : hBmpClose);
621     default : return 0;
622     }
623
624 }
625
626 /***********************************************************************
627  *           MENU_CalcItemSize
628  *
629  * Calculate the size of the menu item and store it in lpitem->rect.
630  */
631 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
632                                INT orgX, INT orgY, BOOL menuBar )
633 {
634     DWORD dwSize;
635     char *p;
636
637     TRACE(menu, "HDC 0x%x at (%d,%d)\n",
638                  hdc, orgX, orgY);
639     debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem, 
640                          (menuBar ? " (MenuBar)" : ""));
641
642     SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
643
644     if (lpitem->fType & MF_OWNERDRAW)
645     {
646         MEASUREITEMSTRUCT mis;
647         mis.CtlType    = ODT_MENU;
648         mis.itemID     = lpitem->wID;
649         mis.itemData   = (DWORD)lpitem->text;
650         mis.itemHeight = 16;
651         mis.itemWidth  = 30;
652         SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
653         lpitem->rect.bottom += mis.itemHeight;
654         lpitem->rect.right  += mis.itemWidth;
655         TRACE(menu, "%08x %dx%d\n",
656                      lpitem->wID, mis.itemWidth, mis.itemHeight);
657         return;
658     } 
659
660     if (lpitem->fType & MF_SEPARATOR)
661     {
662         lpitem->rect.bottom += SEPARATOR_HEIGHT;
663         return;
664     }
665
666     if (!menuBar)
667     {
668         lpitem->rect.right += 2 * check_bitmap_width;
669         if (lpitem->fType & MF_POPUP)
670             lpitem->rect.right += arrow_bitmap_width;
671     }
672
673     if (lpitem->fType & MF_BITMAP)
674     {
675         BITMAP bm;
676         HBITMAP resBmp = 0;
677
678         // Check if there is a magic menu item associated with this item
679         if((LOWORD((int)lpitem->text))<6)
680         {
681             resBmp = MENU_LoadMagicItem((int)lpitem->text,
682                                         (lpitem->fType & MF_HILITE));
683         }
684         else
685             resBmp = (HBITMAP)lpitem->text;
686
687         if (GetObjectA(resBmp, sizeof(bm), &bm ))
688         {
689             lpitem->rect.right  += bm.bmWidth;
690             lpitem->rect.bottom += bm.bmHeight;
691
692         }
693         
694         return;
695         
696     }
697     
698     /* If we get here, then it must be a text item */
699
700     if (IS_STRING_ITEM( lpitem->fType ))
701     {
702         dwSize = GetTextExtent16( hdc, lpitem->text, strlen(lpitem->text) );
703         lpitem->rect.right  += LOWORD(dwSize);
704         if (TWEAK_WineLook == WIN31_LOOK)
705             lpitem->rect.bottom += MAX( HIWORD(dwSize), SYSMETRICS_CYMENU );
706         else
707             lpitem->rect.bottom += MAX (HIWORD(dwSize), sysMetrics[SM_CYMENU]- 1);
708         lpitem->xTab = 0;
709
710         if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
711         else if ((p = strchr( lpitem->text, '\t' )) != NULL)
712         {
713             /* Item contains a tab (only meaningful in popup menus) */
714             lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + 
715                 LOWORD( GetTextExtent16( hdc, lpitem->text,
716                                        (int)(p - lpitem->text) ));
717             lpitem->rect.right += MENU_TAB_SPACE;
718         }
719         else
720         {
721             if (strchr( lpitem->text, '\b' ))
722                 lpitem->rect.right += MENU_TAB_SPACE;
723             lpitem->xTab = lpitem->rect.right - check_bitmap_width 
724                            - arrow_bitmap_width;
725         }
726     }
727 }
728
729
730 /***********************************************************************
731  *           MENU_PopupMenuCalcSize
732  *
733  * Calculate the size of a popup menu.
734  */
735 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
736 {
737     MENUITEM *lpitem;
738     HDC hdc;
739     int start, i;
740     int orgX, orgY, maxX, maxTab, maxTabWidth;
741
742     lppop->Width = lppop->Height = 0;
743     if (lppop->nItems == 0) return;
744     hdc = GetDC( 0 );
745     start = 0;
746     maxX = SYSMETRICS_CXBORDER;
747     while (start < lppop->nItems)
748     {
749         lpitem = &lppop->items[start];
750         orgX = maxX;
751         orgY = SYSMETRICS_CYBORDER;
752
753         maxTab = maxTabWidth = 0;
754
755           /* Parse items until column break or end of menu */
756         for (i = start; i < lppop->nItems; i++, lpitem++)
757         {
758             if ((i != start) &&
759                 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
760
761             if (TWEAK_WineLook > WIN31_LOOK)
762                 ++orgY;
763
764             MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
765
766             if (lpitem->fType & MF_MENUBARBREAK) orgX++;
767             maxX = MAX( maxX, lpitem->rect.right );
768             orgY = lpitem->rect.bottom;
769             if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
770             {
771                 maxTab = MAX( maxTab, lpitem->xTab );
772                 maxTabWidth = MAX(maxTabWidth,lpitem->rect.right-lpitem->xTab);
773             }
774         }
775
776           /* Finish the column (set all items to the largest width found) */
777         maxX = MAX( maxX, maxTab + maxTabWidth );
778         for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
779         {
780             lpitem->rect.right = maxX;
781             if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
782                 lpitem->xTab = maxTab;
783         }
784         lppop->Height = MAX( lppop->Height, orgY );
785     }
786
787     if(TWEAK_WineLook > WIN31_LOOK)
788         lppop->Height++;
789
790     lppop->Width  = maxX;
791     ReleaseDC( 0, hdc );
792 }
793
794
795 /***********************************************************************
796  *           MENU_MenuBarCalcSize
797  *
798  * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
799  * height is off by 1 pixel which causes lengthy window relocations when
800  * active document window is maximized/restored.
801  *
802  * Calculate the size of the menu bar.
803  */
804 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
805                                   LPPOPUPMENU lppop, HWND hwndOwner )
806 {
807     MENUITEM *lpitem;
808     int start, i, orgX, orgY, maxY, helpPos;
809
810     if ((lprect == NULL) || (lppop == NULL)) return;
811     if (lppop->nItems == 0) return;
812     TRACE(menu,"left=%d top=%d right=%d bottom=%d\n", 
813                  lprect->left, lprect->top, lprect->right, lprect->bottom);
814     lppop->Width  = lprect->right - lprect->left;
815     lppop->Height = 0;
816     maxY = lprect->top;
817     start = 0;
818     helpPos = -1;
819     while (start < lppop->nItems)
820     {
821         lpitem = &lppop->items[start];
822         orgX = lprect->left;
823         orgY = maxY;
824
825           /* Parse items until line break or end of menu */
826         for (i = start; i < lppop->nItems; i++, lpitem++)
827         {
828             if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i;
829             if ((i != start) &&
830                 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
831
832             TRACE(menu, "calling MENU_CalcItemSize org=(%d, %d)\n", 
833                          orgX, orgY );
834             debug_print_menuitem ("  item: ", lpitem, "");
835             MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
836
837             if (lpitem->rect.right > lprect->right)
838             {
839                 if (i != start) break;
840                 else lpitem->rect.right = lprect->right;
841             }
842             maxY = MAX( maxY, lpitem->rect.bottom );
843             orgX = lpitem->rect.right;
844         }
845
846           /* Finish the line (set all items to the largest height found) */
847         while (start < i) lppop->items[start++].rect.bottom = maxY;
848     }
849
850     lprect->bottom = maxY;
851     lppop->Height = lprect->bottom - lprect->top;
852
853       /* Flush right all items between the MF_HELP and the last item */
854       /* (if several lines, only move the last line) */
855     if (helpPos != -1)
856     {
857         lpitem = &lppop->items[lppop->nItems-1];
858         orgY = lpitem->rect.top;
859         orgX = lprect->right;
860         for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
861         {
862             if (lpitem->rect.top != orgY) break;    /* Other line */
863             if (lpitem->rect.right >= orgX) break;  /* Too far right already */
864             lpitem->rect.left += orgX - lpitem->rect.right;
865             lpitem->rect.right = orgX;
866             orgX = lpitem->rect.left;
867         }
868     }
869 }
870
871 /***********************************************************************
872  *           MENU_DrawMenuItem
873  *
874  * Draw a single menu item.
875  */
876 static void MENU_DrawMenuItem( HWND hwnd, HDC hdc, MENUITEM *lpitem,
877                                UINT height, BOOL menuBar, UINT odaction )
878 {
879     RECT rect;
880
881     debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
882
883     if (lpitem->fType & MF_SYSMENU)
884     {
885         if( !IsIconic(hwnd) ) {
886             if (TWEAK_WineLook > WIN31_LOOK)
887                 NC_DrawSysButton95( hwnd, hdc,
888                                     lpitem->fState &
889                                     (MF_HILITE | MF_MOUSESELECT) );
890             else
891                 NC_DrawSysButton( hwnd, hdc, 
892                                   lpitem->fState &
893                                   (MF_HILITE | MF_MOUSESELECT) );
894         }
895
896         return;
897     }
898
899     if (lpitem->fType & MF_OWNERDRAW)
900     {
901         DRAWITEMSTRUCT dis;
902
903         dis.CtlType   = ODT_MENU;
904         dis.itemID    = lpitem->wID;
905         dis.itemData  = (DWORD)lpitem->text;
906         dis.itemState = 0;
907         if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
908         if (lpitem->fState & MF_GRAYED)  dis.itemState |= ODS_GRAYED;
909         if (lpitem->fState & MF_HILITE)  dis.itemState |= ODS_SELECTED;
910         dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
911         dis.hwndItem   = hwnd;
912         dis.hDC        = hdc;
913         dis.rcItem     = lpitem->rect;
914         TRACE(menu, "Ownerdraw: itemID=%d, itemState=%d, itemAction=%d, "
915               "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n",dis.itemID,
916               dis.itemState, dis.itemAction, dis.hwndItem, dis.hDC,
917               dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
918               dis.rcItem.bottom );
919         SendMessageA( GetWindow(hwnd,GW_OWNER), WM_DRAWITEM, 0, (LPARAM)&dis );
920         return;
921     }
922
923     if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
924     rect = lpitem->rect;
925
926     /* Draw the background */
927     if (TWEAK_WineLook > WIN31_LOOK) {
928         rect.left += 2;
929         rect.right -= 2;
930
931         /*
932         if(menuBar) {
933             --rect.left;
934             ++rect.bottom;
935             --rect.top;
936         }
937         InflateRect32( &rect, -1, -1 );
938         */
939     }
940
941      if ((lpitem->fState & MF_HILITE) && !(lpitem->fType & MF_BITMAP) )
942         FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
943     else
944         FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
945
946     SetBkMode( hdc, TRANSPARENT );
947
948       /* Draw the separator bar (if any) */
949
950     if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
951     {
952         /* vertical separator */
953         if (TWEAK_WineLook > WIN31_LOOK) {
954             RECT rc = rect;
955             rc.top = 3;
956             rc.bottom = height - 3;
957             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
958         }
959         else {
960             SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
961             MoveTo16( hdc, rect.left, 0 );
962             LineTo( hdc, rect.left, height );
963         }
964     }
965     if (lpitem->fType & MF_SEPARATOR)
966     {
967         /* horizontal separator */
968         if (TWEAK_WineLook > WIN31_LOOK) {
969             RECT rc = rect;
970             rc.left++;
971             rc.right--;
972             rc.top += SEPARATOR_HEIGHT / 2;
973             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
974         }
975         else {
976             SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
977             MoveTo16( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
978             LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
979         }
980
981         return;
982     }
983
984       /* Setup colors */
985
986      if ((lpitem->fState & MF_HILITE) && !(lpitem->fType & MF_BITMAP) )
987     {
988         if (lpitem->fState & MF_GRAYED)
989             SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
990         else
991             SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
992         SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
993     }
994     else
995     {
996         if (lpitem->fState & MF_GRAYED)
997             SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
998         else
999             SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1000         SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1001     }
1002
1003     if (!menuBar)
1004     {
1005         INT     y = rect.top + rect.bottom;
1006
1007           /* Draw the check mark
1008            *
1009            * FIXME:
1010            * Custom checkmark bitmaps are monochrome but not always 1bpp. 
1011            */
1012
1013         if (lpitem->fState & MF_CHECKED)
1014         {
1015             HBITMAP bm =
1016                  lpitem->hCheckBit ? lpitem->hCheckBit :
1017                  ((lpitem->fType & MFT_RADIOCHECK)
1018                   ? hStdRadioCheck : hStdCheck);
1019             HDC hdcMem = CreateCompatibleDC( hdc );
1020
1021             SelectObject( hdcMem, bm );
1022             BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1023                       check_bitmap_width, check_bitmap_height,
1024                       hdcMem, 0, 0, SRCCOPY );
1025             DeleteDC( hdcMem );
1026         } else if (lpitem->hUnCheckBit) {
1027             HDC hdcMem = CreateCompatibleDC( hdc );
1028
1029             SelectObject( hdcMem, lpitem->hUnCheckBit );
1030             BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1031                       check_bitmap_width, check_bitmap_height,
1032                       hdcMem, 0, 0, SRCCOPY );
1033             DeleteDC( hdcMem );
1034         }
1035
1036           /* Draw the popup-menu arrow */
1037
1038         if (lpitem->fType & MF_POPUP)
1039         {
1040             HDC hdcMem = CreateCompatibleDC( hdc );
1041
1042             SelectObject( hdcMem, hStdMnArrow );
1043             BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1044                       (y - arrow_bitmap_height) / 2,
1045                       arrow_bitmap_width, arrow_bitmap_height,
1046                       hdcMem, 0, 0, SRCCOPY );
1047             DeleteDC( hdcMem );
1048         }
1049
1050         rect.left += check_bitmap_width;
1051         rect.right -= arrow_bitmap_width;
1052     }
1053
1054       /* Draw the item text or bitmap */
1055
1056     if (lpitem->fType & MF_BITMAP)
1057     {
1058         HBITMAP resBmp = 0;
1059
1060         HDC hdcMem = CreateCompatibleDC( hdc );
1061
1062         // Check if there is a magic menu item associated with this item
1063         // and load the appropriate bitmap
1064         if((LOWORD((int)lpitem->text)) < 6)
1065         {
1066             resBmp = MENU_LoadMagicItem((int)lpitem->text,
1067                                         (lpitem->fState & MF_HILITE));
1068         }
1069         else
1070             resBmp = (HBITMAP)lpitem->text;
1071         
1072         SelectObject(hdcMem,resBmp );
1073         BitBlt( hdc, rect.left, rect.top+3, rect.right - rect.left+3,
1074                   rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY );
1075         DeleteDC( hdcMem );
1076         
1077         return;
1078
1079     }
1080     /* No bitmap - process text if present */
1081     else if (IS_STRING_ITEM(lpitem->fType))
1082     {
1083         register int i;
1084
1085         if (menuBar)
1086         {
1087             rect.left += MENU_BAR_ITEMS_SPACE / 2;
1088             rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1089             i = strlen( lpitem->text );
1090         }
1091         else
1092         {
1093             for (i = 0; lpitem->text[i]; i++)
1094                 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1095                     break;
1096         }
1097
1098         if((TWEAK_WineLook == WIN31_LOOK) || !(lpitem->fState & MF_GRAYED)) {
1099             DrawTextA( hdc, lpitem->text, i, &rect,
1100                          DT_LEFT | DT_VCENTER | DT_SINGLELINE );
1101         }
1102         else {
1103             if (!(lpitem->fState & MF_HILITE))
1104             {
1105                 ++rect.left;
1106                 ++rect.top;
1107                 ++rect.right;
1108                 ++rect.bottom;
1109                 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1110                 DrawTextA( hdc, lpitem->text, i, &rect,
1111                              DT_LEFT | DT_VCENTER | DT_SINGLELINE );
1112                 --rect.left;
1113                 --rect.top;
1114                 --rect.right;
1115                 --rect.bottom;
1116             }
1117             SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1118             DrawTextA( hdc, lpitem->text, i, &rect,
1119                          DT_LEFT | DT_VCENTER | DT_SINGLELINE );
1120         }
1121
1122         if (lpitem->text[i])  /* There's a tab or flush-right char */
1123         {
1124             if (lpitem->text[i] == '\t')
1125             {
1126                 rect.left = lpitem->xTab;
1127                 DrawTextA( hdc, lpitem->text + i + 1, -1, &rect,
1128                              DT_LEFT | DT_VCENTER | DT_SINGLELINE );
1129             }
1130             else DrawTextA( hdc, lpitem->text + i + 1, -1, &rect,
1131                               DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
1132         }
1133     }
1134 }
1135
1136
1137 /***********************************************************************
1138  *           MENU_DrawPopupMenu
1139  *
1140  * Paint a popup menu.
1141  */
1142 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1143 {
1144     HBRUSH hPrevBrush = 0;
1145     RECT rect;
1146
1147     GetClientRect( hwnd, &rect );
1148
1149 /*    if(!TWEAK_Win95Look) { */
1150         rect.bottom -= POPUP_YSHADE * SYSMETRICS_CYBORDER;
1151         rect.right -= POPUP_XSHADE * SYSMETRICS_CXBORDER;
1152 /*    } */
1153
1154     if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) )))
1155     {
1156         HPEN hPrevPen;
1157         
1158         Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1159
1160         hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1161         if( hPrevPen )
1162         {
1163             INT ropPrev, i;
1164             POPUPMENU *menu;
1165
1166             /* draw 3-d shade */
1167             if(TWEAK_WineLook == WIN31_LOOK) {
1168                 SelectObject( hdc, hShadeBrush );
1169                 SetBkMode( hdc, TRANSPARENT );
1170                 ropPrev = SetROP2( hdc, R2_MASKPEN );
1171
1172                 i = rect.right;         /* why SetBrushOrg() doesn't? */
1173                 PatBlt( hdc, i & 0xfffffffe,
1174                           rect.top + POPUP_YSHADE*SYSMETRICS_CYBORDER, 
1175                           i%2 + POPUP_XSHADE*SYSMETRICS_CXBORDER,
1176                           rect.bottom - rect.top, 0x00a000c9 );
1177                 i = rect.bottom;
1178                 PatBlt( hdc, rect.left + POPUP_XSHADE*SYSMETRICS_CXBORDER,
1179                           i & 0xfffffffe,rect.right - rect.left,
1180                           i%2 + POPUP_YSHADE*SYSMETRICS_CYBORDER, 0x00a000c9 );
1181                 SelectObject( hdc, hPrevPen );
1182                 SelectObject( hdc, hPrevBrush );
1183                 SetROP2( hdc, ropPrev );
1184             }
1185             else
1186                 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1187
1188             /* draw menu items */
1189
1190             menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1191             if (menu && menu->nItems)
1192             {
1193                 MENUITEM *item;
1194                 UINT u;
1195
1196                 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1197                     MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE,
1198                                        ODA_DRAWENTIRE );
1199
1200             }
1201         } else SelectObject( hdc, hPrevBrush );
1202     }
1203 }
1204
1205
1206 /***********************************************************************
1207  *           MENU_DrawMenuBar
1208  *
1209  * Paint a menu bar. Returns the height of the menu bar.
1210  */
1211 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1212                          BOOL suppress_draw)
1213 {
1214     LPPOPUPMENU lppop;
1215     UINT i;
1216     WND *wndPtr = WIN_FindWndPtr( hwnd );
1217     
1218     lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( (HMENU16)wndPtr->wIDmenu );
1219     if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
1220     TRACE(menu,"(%04x, %p, %p); !\n", 
1221                  hDC, lprect, lppop);
1222     if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1223     lprect->bottom = lprect->top + lppop->Height;
1224     if (suppress_draw) return lppop->Height;
1225     
1226     FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1227
1228     if (TWEAK_WineLook == WIN31_LOOK) {
1229         SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1230         MoveTo16( hDC, lprect->left, lprect->bottom );
1231         LineTo( hDC, lprect->right, lprect->bottom );
1232     }
1233     else {
1234         SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1235         MoveTo16( hDC, lprect->left, lprect->bottom );
1236         LineTo( hDC, lprect->right, lprect->bottom );
1237     }
1238
1239     if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
1240     for (i = 0; i < lppop->nItems; i++)
1241     {
1242         MENU_DrawMenuItem( hwnd, hDC, &lppop->items[i], lppop->Height, TRUE,
1243                            ODA_DRAWENTIRE );
1244     }
1245     return lppop->Height;
1246
1247
1248
1249 /***********************************************************************
1250  *           MENU_PatchResidentPopup
1251  */
1252 BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
1253 {
1254     if( pTopPopupWnd )
1255     {
1256         HTASK16 hTask = 0;
1257
1258         TRACE(menu,"patching resident popup: %04x %04x [%04x %04x]\n", 
1259                 checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTopPopupWnd->hmemTaskQ, 
1260                 pTopPopupWnd->owner ? pTopPopupWnd->owner->hwndSelf : 0);
1261
1262         switch( checkQueue )
1263         {
1264             case 0: /* checkWnd is the new popup owner */
1265                  if( checkWnd )
1266                  {
1267                      pTopPopupWnd->owner = checkWnd;
1268                      if( pTopPopupWnd->hmemTaskQ != checkWnd->hmemTaskQ )
1269                          hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
1270                  }
1271                  break;
1272
1273             case 0xFFFF: /* checkWnd is destroyed */
1274                  if( pTopPopupWnd->owner == checkWnd )
1275                      pTopPopupWnd->owner = NULL;
1276                  return TRUE; 
1277
1278             default: /* checkQueue is exiting */
1279                  if( pTopPopupWnd->hmemTaskQ == checkQueue )
1280                  {
1281                      hTask = QUEUE_GetQueueTask( pTopPopupWnd->hmemTaskQ );
1282                      hTask = TASK_GetNextTask( hTask );
1283                  }
1284                  break;
1285         }
1286
1287         if( hTask )
1288         {
1289             TDB* task = (TDB*)GlobalLock16( hTask );
1290             if( task )
1291             {
1292                 pTopPopupWnd->hInstance = task->hInstance;
1293                 pTopPopupWnd->hmemTaskQ = task->hQueue;
1294                 return TRUE;
1295             } 
1296             else WARN(menu,"failed to patch resident popup.\n");
1297         } 
1298     }
1299     return FALSE;
1300 }
1301
1302 /***********************************************************************
1303  *           MENU_ShowPopup
1304  *
1305  * Display a popup menu.
1306  */
1307 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1308                               INT x, INT y, INT xanchor, INT yanchor )
1309 {
1310     POPUPMENU   *menu;
1311     WND         *wndOwner = NULL;
1312
1313     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
1314     if (menu->FocusedItem != NO_SELECTED_ITEM)
1315     {
1316         menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1317         menu->FocusedItem = NO_SELECTED_ITEM;
1318     }
1319
1320     if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
1321     {
1322         UINT    width, height;
1323
1324         MENU_PopupMenuCalcSize( menu, hwndOwner );
1325
1326         /* adjust popup menu pos so that it fits within the desktop */
1327
1328         width = menu->Width + SYSMETRICS_CXBORDER;
1329         height = menu->Height + SYSMETRICS_CYBORDER; 
1330
1331         if( x + width > SYSMETRICS_CXSCREEN )
1332         {
1333             if( xanchor )
1334                 x -= width - xanchor;
1335             if( x + width > SYSMETRICS_CXSCREEN)
1336                 x = SYSMETRICS_CXSCREEN - width;
1337         }
1338         if( x < 0 ) x = 0;
1339
1340         if( y + height > SYSMETRICS_CYSCREEN )
1341         { 
1342             if( yanchor )
1343                 y -= height + yanchor;
1344             if( y + height > SYSMETRICS_CYSCREEN )
1345                 y = SYSMETRICS_CYSCREEN - height;
1346         }
1347         if( y < 0 ) y = 0;
1348
1349         width += POPUP_XSHADE * SYSMETRICS_CXBORDER;    /* add space for shading */
1350         height += POPUP_YSHADE * SYSMETRICS_CYBORDER;
1351
1352         /* NOTE: In Windows, top menu popup is not owned. */
1353         if (!pTopPopupWnd)      /* create top level popup menu window */
1354         {
1355             assert( uSubPWndLevel == 0 );
1356
1357             pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1358                                           WS_POPUP, x, y, width, height,
1359                                           hwndOwner, 0, wndOwner->hInstance,
1360                                           (LPVOID)hmenu ));
1361             if (!pTopPopupWnd) return FALSE;
1362             menu->hWnd = pTopPopupWnd->hwndSelf;
1363         } 
1364         else
1365             if( uSubPWndLevel )
1366             {
1367                 /* create a new window for the submenu */
1368
1369                 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1370                                           WS_POPUP, x, y, width, height,
1371                                           menu->hWnd, 0, wndOwner->hInstance,
1372                                           (LPVOID)hmenu );
1373                 if( !menu->hWnd ) return FALSE;
1374             }
1375             else /* top level popup menu window already exists */
1376             {
1377                 menu->hWnd = pTopPopupWnd->hwndSelf;
1378
1379                 MENU_PatchResidentPopup( 0, wndOwner );
1380                 SendMessage16( pTopPopupWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);  
1381
1382                 /* adjust its size */
1383
1384                 SetWindowPos( menu->hWnd, 0, x, y, width, height,
1385                                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
1386             }
1387
1388         uSubPWndLevel++;        /* menu level counter */
1389
1390       /* Display the window */
1391
1392         SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1393                         SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1394         UpdateWindow( menu->hWnd );
1395         return TRUE;
1396     }
1397     return FALSE;
1398 }
1399
1400
1401 /***********************************************************************
1402  *           MENU_SelectItem
1403  */
1404 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1405                              BOOL sendMenuSelect )
1406 {
1407     LPPOPUPMENU lppop;
1408     HDC hdc;
1409
1410     lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1411     if (!lppop->nItems) return;
1412
1413     if ((wIndex != NO_SELECTED_ITEM) && 
1414         (lppop->items[wIndex].fType & MF_SEPARATOR))
1415         wIndex = NO_SELECTED_ITEM;
1416
1417     if (lppop->FocusedItem == wIndex) return;
1418     if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1419     else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1420
1421       /* Clear previous highlighted item */
1422     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
1423     {
1424         lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1425         MENU_DrawMenuItem(lppop->hWnd,hdc,&lppop->items[lppop->FocusedItem],
1426                           lppop->Height, !(lppop->wFlags & MF_POPUP),
1427                           ODA_SELECT );
1428     }
1429
1430       /* Highlight new item (if any) */
1431     lppop->FocusedItem = wIndex;
1432     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
1433     {
1434         lppop->items[lppop->FocusedItem].fState |= MF_HILITE;
1435         MENU_DrawMenuItem( lppop->hWnd, hdc, &lppop->items[lppop->FocusedItem],
1436                            lppop->Height, !(lppop->wFlags & MF_POPUP),
1437                            ODA_SELECT );
1438         if (sendMenuSelect)
1439         {
1440             MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1441             SendMessage16( hwndOwner, WM_MENUSELECT, ip->wID,
1442                            MAKELONG(ip->fType | (ip->fState | MF_MOUSESELECT),
1443                                     hmenu) );
1444         }
1445     }
1446     else if (sendMenuSelect) {
1447         SendMessage16( hwndOwner, WM_MENUSELECT, hmenu,
1448                        MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) ); 
1449     }
1450     ReleaseDC( lppop->hWnd, hdc );
1451 }
1452
1453
1454 /***********************************************************************
1455  *           MENU_MoveSelection
1456  *
1457  * Moves currently selected item according to the offset parameter.
1458  * If there is no selection then it should select the last item if
1459  * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1460  */
1461 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1462 {
1463     INT i;
1464     POPUPMENU *menu;
1465
1466     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1467     if (!menu->items) return;
1468
1469     if ( menu->FocusedItem != NO_SELECTED_ITEM )
1470     {
1471         if( menu->nItems == 1 ) return; else
1472         for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems 
1473                                             ; i += offset)
1474             if (!(menu->items[i].fType & MF_SEPARATOR))
1475             {
1476                 MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
1477                 return;
1478             }
1479     }
1480
1481     for ( i = (offset > 0) ? 0 : menu->nItems - 1; 
1482                   i >= 0 && i < menu->nItems ; i += offset)
1483         if (!(menu->items[i].fType & MF_SEPARATOR))
1484         {
1485             MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
1486             return;
1487         }
1488 }
1489
1490
1491 /**********************************************************************
1492  *         MENU_SetItemData
1493  *
1494  * Set an item flags, id and text ptr. Called by InsertMenu() and
1495  * ModifyMenu().
1496  */
1497 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1498                                 LPCSTR str )
1499 {
1500     LPSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1501
1502     debug_print_menuitem("MENU_SetItemData from: ", item, "");
1503
1504     if (IS_STRING_ITEM(flags))
1505     {
1506         if (!str || !*str)
1507         {
1508             flags |= MF_SEPARATOR;
1509             item->text = NULL;
1510         }
1511         else
1512         {
1513             LPSTR text;
1514             /* Item beginning with a backspace is a help item */
1515             if (*str == '\b')
1516             {
1517                 flags |= MF_HELP;
1518                 str++;
1519             }
1520             if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1521             item->text = text;
1522         }
1523     }
1524     else if (flags & MF_BITMAP) item->text = (LPSTR)(HBITMAP)LOWORD(str);
1525     else item->text = NULL;
1526
1527     if (flags & MF_OWNERDRAW) 
1528         item->dwItemData = (DWORD)str;
1529     else
1530         item->dwItemData = 0;
1531
1532     if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1533         DestroyMenu( item->hSubMenu );   /* ModifyMenu() spec */
1534
1535     if (flags & MF_POPUP)
1536     {
1537         POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR((UINT16)id);
1538         if (IS_A_MENU(menu)) menu->wFlags |= MF_POPUP;
1539         else
1540         {
1541             item->wID = 0;
1542             item->hSubMenu = 0;
1543             item->fType = 0;
1544             item->fState = 0;
1545             return FALSE;
1546         }
1547     } 
1548
1549     item->wID = id;
1550     if (flags & MF_POPUP)
1551       item->hSubMenu = id;
1552
1553     if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1554       flags |= MF_POPUP; /* keep popup */
1555
1556     item->fType = flags & TYPE_MASK;
1557     item->fState = (flags & STATE_MASK) &
1558         ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1559
1560
1561     /* Don't call SetRectEmpty here! */
1562
1563
1564     if (prevText) HeapFree( SystemHeap, 0, prevText );
1565
1566     debug_print_menuitem("MENU_SetItemData to  : ", item, "");
1567     return TRUE;
1568 }
1569
1570
1571 /**********************************************************************
1572  *         MENU_InsertItem
1573  *
1574  * Insert a new item into a menu.
1575  */
1576 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1577 {
1578     MENUITEM *newItems;
1579     POPUPMENU *menu;
1580
1581     if (!(menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu))) 
1582     {
1583         WARN(menu, "%04x not a menu handle\n",
1584                       hMenu );
1585         return NULL;
1586     }
1587
1588     /* Find where to insert new item */
1589
1590     if ((flags & MF_BYPOSITION) &&
1591         ((pos == (UINT)-1) || (pos == menu->nItems)))
1592     {
1593         /* Special case: append to menu */
1594         /* Some programs specify the menu length to do that */
1595         pos = menu->nItems;
1596     }
1597     else
1598     {
1599         if (!MENU_FindItem( &hMenu, &pos, flags )) 
1600         {
1601             WARN(menu, "item %x not found\n",
1602                           pos );
1603             return NULL;
1604         }
1605         if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
1606         {
1607             WARN(menu,"%04x not a menu handle\n",
1608                          hMenu);
1609             return NULL;
1610         }
1611     }
1612
1613     /* Create new items array */
1614
1615     newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1616     if (!newItems)
1617     {
1618         WARN(menu, "allocation failed\n" );
1619         return NULL;
1620     }
1621     if (menu->nItems > 0)
1622     {
1623           /* Copy the old array into the new */
1624         if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1625         if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1626                                         (menu->nItems-pos)*sizeof(MENUITEM) );
1627         HeapFree( SystemHeap, 0, menu->items );
1628     }
1629     menu->items = newItems;
1630     menu->nItems++;
1631     memset( &newItems[pos], 0, sizeof(*newItems) );
1632     return &newItems[pos];
1633 }
1634
1635
1636 /**********************************************************************
1637  *         MENU_ParseResource
1638  *
1639  * Parse a standard menu resource and add items to the menu.
1640  * Return a pointer to the end of the resource.
1641  */
1642 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1643 {
1644     WORD flags, id = 0;
1645     LPCSTR str;
1646
1647     do
1648     {
1649         flags = GET_WORD(res);
1650         res += sizeof(WORD);
1651         if (!(flags & MF_POPUP))
1652         {
1653             id = GET_WORD(res);
1654             res += sizeof(WORD);
1655         }
1656         if (!IS_STRING_ITEM(flags))
1657             ERR(menu, "not a string item %04x\n", flags );
1658         str = res;
1659         if (!unicode) res += strlen(str) + 1;
1660         else res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1661         if (flags & MF_POPUP)
1662         {
1663             HMENU hSubMenu = CreatePopupMenu();
1664             if (!hSubMenu) return NULL;
1665             if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1666                 return NULL;
1667             if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1668             else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1669         }
1670         else  /* Not a popup */
1671         {
1672             if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1673             else AppendMenuW( hMenu, flags, id,
1674                                 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1675         }
1676     } while (!(flags & MF_END));
1677     return res;
1678 }
1679
1680
1681 /**********************************************************************
1682  *         MENUEX_ParseResource
1683  *
1684  * Parse an extended menu resource and add items to the menu.
1685  * Return a pointer to the end of the resource.
1686  */
1687 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1688 {
1689     WORD resinfo;
1690     do {
1691         MENUITEMINFOW mii;
1692
1693         mii.cbSize = sizeof(mii);
1694         mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1695         mii.fType = GET_DWORD(res);
1696         res += sizeof(DWORD);
1697         mii.fState = GET_DWORD(res);
1698         res += sizeof(DWORD);
1699         mii.wID = GET_DWORD(res);
1700         res += sizeof(DWORD);
1701         resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte.  */
1702         res += sizeof(WORD);
1703         /* Align the text on a word boundary.  */
1704         res += (~((int)res - 1)) & 1;
1705         mii.dwTypeData = (LPWSTR) res;
1706         res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
1707         /* Align the following fields on a dword boundary.  */
1708         res += (~((int)res - 1)) & 3;
1709
1710         /* FIXME: This is inefficient and cannot be optimised away by gcc.  */
1711         {
1712             LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
1713                                            0, mii.dwTypeData);
1714             TRACE(menu, "Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1715                          mii.fType, mii.fState, mii.wID, resinfo, newstr);
1716             HeapFree( GetProcessHeap(), 0, newstr );
1717         }
1718
1719         if (resinfo & 1) {      /* Pop-up? */
1720             /* DWORD helpid = GET_DWORD(res); FIXME: use this.  */
1721             res += sizeof(DWORD);
1722             mii.hSubMenu = CreatePopupMenu();
1723             if (!mii.hSubMenu)
1724                 return NULL;
1725             if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
1726                 DestroyMenu(mii.hSubMenu);
1727                 return NULL;
1728         }
1729             mii.fMask |= MIIM_SUBMENU;
1730             mii.fType |= MF_POPUP;
1731         }
1732         InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
1733     } while (!(resinfo & MF_END));
1734     return res;
1735 }
1736
1737
1738 /***********************************************************************
1739  *           MENU_GetSubPopup
1740  *
1741  * Return the handle of the selected sub-popup menu (if any).
1742  */
1743 static HMENU MENU_GetSubPopup( HMENU hmenu )
1744 {
1745     POPUPMENU *menu;
1746     MENUITEM *item;
1747
1748     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1749
1750     if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
1751
1752     item = &menu->items[menu->FocusedItem];
1753     if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
1754         return item->hSubMenu;
1755     return 0;
1756 }
1757
1758
1759 /***********************************************************************
1760  *           MENU_HideSubPopups
1761  *
1762  * Hide the sub-popup menus of this menu.
1763  */
1764 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
1765                                 BOOL sendMenuSelect )
1766 {
1767     POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR( hmenu );;
1768
1769     if (menu && uSubPWndLevel)
1770     {
1771         HMENU hsubmenu;
1772         POPUPMENU *submenu;
1773         MENUITEM *item;
1774
1775         if (menu->FocusedItem != NO_SELECTED_ITEM)
1776         {
1777             item = &menu->items[menu->FocusedItem];
1778             if (!(item->fType & MF_POPUP) ||
1779                 !(item->fState & MF_MOUSESELECT)) return;
1780             item->fState &= ~MF_MOUSESELECT;
1781             hsubmenu = item->hSubMenu;
1782         } else return;
1783
1784         submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
1785         MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
1786         MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect );
1787
1788         if (submenu->hWnd == pTopPopupWnd->hwndSelf ) 
1789         {
1790             ShowWindow( submenu->hWnd, SW_HIDE );
1791             uSubPWndLevel = 0;
1792         }
1793         else
1794         {
1795             DestroyWindow( submenu->hWnd );
1796             submenu->hWnd = 0;
1797         }
1798     }
1799 }
1800
1801
1802 /***********************************************************************
1803  *           MENU_ShowSubPopup
1804  *
1805  * Display the sub-menu of the selected item of this menu.
1806  * Return the handle of the submenu, or hmenu if no submenu to display.
1807  */
1808 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
1809                                   BOOL selectFirst )
1810 {
1811     RECT rect;
1812     POPUPMENU *menu;
1813     MENUITEM *item;
1814     WND *wndPtr;
1815     HDC hdc;
1816
1817     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
1818
1819     if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
1820          (menu->FocusedItem == NO_SELECTED_ITEM)) return hmenu;
1821
1822     item = &menu->items[menu->FocusedItem];
1823     if (!(item->fType & MF_POPUP) ||
1824          (item->fState & (MF_GRAYED | MF_DISABLED))) return hmenu;
1825
1826     /* message must be send before using item,
1827        because nearly everything may by changed by the application ! */
1828
1829     SendMessage16( hwndOwner, WM_INITMENUPOPUP, (WPARAM16)item->hSubMenu,
1830                    MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
1831
1832     item = &menu->items[menu->FocusedItem];
1833     rect = item->rect;
1834
1835     /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
1836     if (!(item->fState & MF_HILITE)) 
1837     {
1838         if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
1839         else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1840         item->fState |= MF_HILITE;
1841         MENU_DrawMenuItem( menu->hWnd, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE ); 
1842         ReleaseDC( menu->hWnd, hdc );
1843     }
1844     if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
1845       item->rect = rect;
1846
1847     item->fState |= MF_MOUSESELECT;
1848
1849     if (IS_SYSTEM_MENU(menu))
1850     {
1851         MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, wndPtr->class->style);
1852
1853         NC_GetSysPopupPos( wndPtr, &rect );
1854         rect.top = rect.bottom;
1855         rect.right = SYSMETRICS_CXSIZE;
1856         rect.bottom = SYSMETRICS_CYSIZE;
1857     }
1858     else
1859     {
1860         if (menu->wFlags & MF_POPUP)
1861         {
1862             rect.left = wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width;
1863             rect.top = wndPtr->rectWindow.top + item->rect.top;
1864             rect.right = item->rect.left - item->rect.right + 2*arrow_bitmap_width;
1865             rect.bottom = item->rect.top - item->rect.bottom;
1866         }
1867         else
1868         {
1869             rect.left = wndPtr->rectWindow.left + item->rect.left;
1870             rect.top = wndPtr->rectWindow.top + item->rect.bottom;
1871             rect.right = item->rect.right - item->rect.left;
1872             rect.bottom = item->rect.bottom - item->rect.top;
1873         }
1874     }
1875
1876     MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
1877                     rect.left, rect.top, rect.right, rect.bottom );
1878     if (selectFirst)
1879         MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
1880     return item->hSubMenu;
1881 }
1882
1883 /***********************************************************************
1884  *           MENU_PtMenu
1885  *
1886  * Walks menu chain trying to find a menu pt maps to.
1887  */
1888 static HMENU MENU_PtMenu( HMENU hMenu, POINT16 pt )
1889 {
1890    POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
1891    register UINT ht = menu->FocusedItem;
1892
1893    /* try subpopup first (if any) */
1894     ht = (ht != NO_SELECTED_ITEM &&
1895           (menu->items[ht].fType & MF_POPUP) &&
1896           (menu->items[ht].fState & MF_MOUSESELECT))
1897         ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
1898
1899    if( !ht )    /* check the current window (avoiding WM_HITTEST) */
1900    {
1901         ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt );
1902         if( menu->wFlags & MF_POPUP )
1903             ht =  (ht != (UINT)HTNOWHERE && 
1904                    ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
1905         else
1906         {
1907             WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
1908
1909             ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu)
1910                  : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0;
1911         }
1912    }
1913    return (HMENU)ht;
1914 }
1915 /***********************************************************************
1916  *           MENU_ExecFocusedItem
1917  *
1918  * Execute a menu item (for instance when user pressed Enter).
1919  * Return the wID of the executed item. Otherwise, zero indicating
1920  * that no menu item wase executed;
1921  */
1922 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu )
1923 {
1924     MENUITEM *item;
1925     POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
1926     if (!menu || !menu->nItems || 
1927         (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
1928
1929     item = &menu->items[menu->FocusedItem];
1930
1931     TRACE(menu, "%08x %08x %08x\n",
1932                  hMenu, item->wID, item->hSubMenu);
1933
1934     if (!(item->fType & MF_POPUP))
1935     {
1936         if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
1937         {
1938             if( menu->wFlags & MF_SYSMENU )
1939             {
1940                 PostMessage16( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
1941                                MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
1942             }
1943             else
1944             {
1945                 PostMessage16( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
1946             }
1947             return item->wID;
1948         }
1949         else return 0;
1950     }
1951     else
1952     {
1953         pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hMenu, TRUE );
1954         return 0;
1955     }
1956 }
1957
1958 /***********************************************************************
1959  *           MENU_SwitchTracking
1960  *
1961  * Helper function for menu navigation routines.
1962  */
1963 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
1964 {
1965     POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
1966     POPUPMENU *topmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
1967
1968     if( pmt->hTopMenu != hPtMenu &&
1969         !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
1970     {
1971         /* both are top level menus (system and menu-bar) */
1972
1973         MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
1974         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
1975         pmt->hTopMenu = hPtMenu;
1976     }
1977     else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
1978     MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE );
1979 }
1980
1981
1982 /***********************************************************************
1983  *           MENU_ButtonDown
1984  *
1985  * Return TRUE if we can go on with menu tracking.
1986  */
1987 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu )
1988 {
1989     if (hPtMenu)
1990     {
1991         UINT id = 0;
1992         POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
1993         MENUITEM *item;
1994
1995         if( IS_SYSTEM_MENU(ptmenu) )
1996             item = ptmenu->items;
1997         else
1998             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
1999
2000         if( item )
2001         {
2002             if( ptmenu->FocusedItem == id )
2003             {
2004                 /* nothing to do with already selected non-popup */
2005                 if( !(item->fType & MF_POPUP) ) return TRUE;
2006
2007                 if( item->fState & MF_MOUSESELECT )
2008                 {
2009                     if( ptmenu->wFlags & MF_POPUP )
2010                     {
2011                         /* hide selected subpopup */
2012
2013                         MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, TRUE );
2014                         pmt->hCurrentMenu = hPtMenu;
2015                         return TRUE;
2016                     }
2017                     return FALSE; /* shouldn't get here */
2018                 } 
2019             }
2020             else MENU_SwitchTracking( pmt, hPtMenu, id );
2021
2022             /* try to display a subpopup */
2023
2024             pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
2025             return TRUE;
2026         } 
2027         else WARN(menu, "\tunable to find clicked item!\n");
2028     }
2029     return FALSE;
2030 }
2031
2032 /***********************************************************************
2033  *           MENU_ButtonUp
2034  *
2035  * Return the the value of MENU_ExecFocusedItem if
2036  * the selected item was not a popup
2037  * 1 if the item was a popup
2038  * 0 otherwise.
2039  * A zero return value indicates that we can't go on with menu tracking.
2040  */
2041 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu )
2042 {
2043     if (hPtMenu)
2044     {
2045         UINT id = 0;
2046         POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
2047         MENUITEM *item;
2048
2049         if( IS_SYSTEM_MENU(ptmenu) )
2050             item = ptmenu->items;
2051         else
2052             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2053
2054         if( item && (ptmenu->FocusedItem == id ))
2055         {
2056             if( !(item->fType & MF_POPUP) )
2057                 return MENU_ExecFocusedItem( pmt, hPtMenu );
2058             hPtMenu = item->hSubMenu;
2059             if( hPtMenu == pmt->hCurrentMenu )
2060             {
2061                 /* Select first item of sub-popup */    
2062
2063                 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, NO_SELECTED_ITEM, FALSE );
2064                 MENU_MoveSelection( pmt->hOwnerWnd, hPtMenu, ITEM_NEXT );
2065             }
2066             return 1;
2067         }
2068     }
2069     return 0;
2070 }
2071
2072
2073 /***********************************************************************
2074  *           MENU_MouseMove
2075  *
2076  * Return TRUE if we can go on with menu tracking.
2077  */
2078 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu )
2079 {
2080     UINT id = NO_SELECTED_ITEM;
2081     POPUPMENU *ptmenu = NULL;
2082
2083     if( hPtMenu )
2084     {
2085         ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
2086         if( IS_SYSTEM_MENU(ptmenu) )
2087             id = 0;
2088         else
2089             MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2090     } 
2091
2092     if( id == NO_SELECTED_ITEM )
2093     {
2094         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, 
2095                          NO_SELECTED_ITEM, TRUE );
2096     }
2097     else if( ptmenu->FocusedItem != id )
2098     {
2099             MENU_SwitchTracking( pmt, hPtMenu, id );
2100             pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
2101     }
2102     return TRUE;
2103 }
2104
2105
2106 /***********************************************************************
2107  *           MENU_DoNextMenu
2108  *
2109  * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2110  */
2111 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2112 {
2113     POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
2114
2115     if( (vk == VK_LEFT &&  menu->FocusedItem == 0 ) ||
2116         (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2117     {
2118         WND*    wndPtr;
2119         HMENU hNewMenu;
2120         HWND  hNewWnd;
2121         UINT  id = 0;
2122         LRESULT l = SendMessage16( pmt->hOwnerWnd, WM_NEXTMENU, (WPARAM16)vk, 
2123                 (IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
2124
2125         TRACE(menu,"%04x [%04x] -> %04x [%04x]\n",
2126                      (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
2127
2128         if( l == 0 )
2129         {
2130             wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
2131
2132             hNewWnd = pmt->hOwnerWnd;
2133             if( IS_SYSTEM_MENU(menu) )
2134             {
2135                 /* switch to the menu bar */
2136
2137                 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu ) 
2138                     return FALSE;
2139
2140                 hNewMenu = wndPtr->wIDmenu;
2141                 if( vk == VK_LEFT )
2142                 {
2143                     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hNewMenu );
2144                     id = menu->nItems - 1;
2145                 }
2146             }
2147             else if( wndPtr->dwStyle & WS_SYSMENU ) 
2148             {
2149                 /* switch to the system menu */
2150                 hNewMenu = wndPtr->hSysMenu; 
2151             }
2152             else return FALSE;
2153         }
2154         else    /* application returned a new menu to switch to */
2155         {
2156             hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
2157
2158             if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2159             {
2160                 wndPtr = WIN_FindWndPtr(hNewWnd);
2161
2162                 if( wndPtr->dwStyle & WS_SYSMENU &&
2163                     GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
2164                 {
2165                     /* get the real system menu */
2166                     hNewMenu =  wndPtr->hSysMenu;
2167                 }
2168                 else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
2169                 {
2170                     /* FIXME: Not sure what to do here, perhaps,
2171                      * try to track hNewMenu as a popup? */
2172
2173                     TRACE(menu," -- got confused.\n");
2174                     return FALSE;
2175                 }
2176             }
2177             else return FALSE;
2178         }
2179
2180         if( hNewMenu != pmt->hTopMenu )
2181         {
2182             MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
2183             if( pmt->hCurrentMenu != pmt->hTopMenu ) 
2184                 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2185         }
2186
2187         if( hNewWnd != pmt->hOwnerWnd )
2188         {
2189             ReleaseCapture(); 
2190             pmt->hOwnerWnd = hNewWnd;
2191             EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2192         }
2193
2194         pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2195         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE ); 
2196
2197         return TRUE;
2198     }
2199     return FALSE;
2200 }
2201
2202 /***********************************************************************
2203  *           MENU_SuspendPopup
2204  *
2205  * The idea is not to show the popup if the next input message is
2206  * going to hide it anyway.
2207  */
2208 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2209 {
2210     MSG16 msg;
2211
2212     msg.hwnd = pmt->hOwnerWnd;
2213
2214     PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2215     pmt->trackFlags |= TF_SKIPREMOVE;
2216
2217     switch( uMsg )
2218     {
2219         case WM_KEYDOWN:
2220              PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2221              if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2222              {
2223                  PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2224                  PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2225                  if( msg.message == WM_KEYDOWN &&
2226                     (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2227                  {
2228                      pmt->trackFlags |= TF_SUSPENDPOPUP;
2229                      return TRUE;
2230                  }
2231              }
2232              break;
2233     }
2234
2235     /* failures go through this */
2236     pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2237     return FALSE;
2238 }
2239
2240 /***********************************************************************
2241  *           MENU_KeyLeft
2242  *
2243  * Handle a VK_LEFT key event in a menu. 
2244  */
2245 static void MENU_KeyLeft( MTRACKER* pmt )
2246 {
2247     POPUPMENU *menu;
2248     HMENU hmenutmp, hmenuprev;
2249     UINT  prevcol;
2250
2251     hmenuprev = hmenutmp = pmt->hTopMenu;
2252     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenutmp );
2253
2254     /* Try to move 1 column left (if possible) */
2255     if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) != 
2256         NO_SELECTED_ITEM ) {
2257         
2258         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2259                          prevcol, TRUE );
2260         return;
2261     }
2262
2263     /* close topmost popup */
2264     while (hmenutmp != pmt->hCurrentMenu)
2265     {
2266         hmenuprev = hmenutmp;
2267         hmenutmp = MENU_GetSubPopup( hmenuprev );
2268     }
2269
2270     MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2271     pmt->hCurrentMenu = hmenuprev; 
2272
2273     if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2274     {
2275         /* move menu bar selection if no more popups are left */
2276
2277         if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2278              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2279
2280         if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2281         {
2282            /* A sublevel menu was displayed - display the next one
2283             * unless there is another displacement coming up */
2284
2285             if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2286                 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd,
2287                                                 pmt->hTopMenu, TRUE );
2288         }
2289     }
2290 }
2291
2292
2293 /***********************************************************************
2294  *           MENU_KeyRight
2295  *
2296  * Handle a VK_RIGHT key event in a menu.
2297  */
2298 static void MENU_KeyRight( MTRACKER* pmt )
2299 {
2300     HMENU hmenutmp;
2301     POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
2302     UINT  nextcol;
2303
2304     TRACE(menu, "MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2305                   pmt->hCurrentMenu,
2306                   ((POPUPMENU *)USER_HEAP_LIN_ADDR(pmt->hCurrentMenu))->
2307                      items[0].text,
2308                   pmt->hTopMenu, menu->items[0].text );
2309
2310     if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2311     {
2312         /* If already displaying a popup, try to display sub-popup */
2313
2314         hmenutmp = pmt->hCurrentMenu;
2315         pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hmenutmp, TRUE );
2316
2317         /* if subpopup was displayed then we are done */
2318         if (hmenutmp != pmt->hCurrentMenu) return;
2319     }
2320
2321     /* Check to see if there's another column */
2322     if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) != 
2323         NO_SELECTED_ITEM ) {
2324         TRACE(menu, "Going to %d.\n", nextcol );
2325         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2326                          nextcol, TRUE );
2327         return;
2328     }
2329
2330     if (!(menu->wFlags & MF_POPUP))     /* menu bar tracking */
2331     {
2332         if( pmt->hCurrentMenu != pmt->hTopMenu )
2333         {
2334             MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2335             hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2336         } else hmenutmp = 0;
2337
2338         /* try to move to the next item */
2339         if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2340              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2341
2342         if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2343             if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2344                 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, 
2345                                                        pmt->hTopMenu, TRUE );
2346     }
2347 }
2348
2349 /***********************************************************************
2350  *           MENU_TrackMenu
2351  *
2352  * Menu tracking code.
2353  */
2354 static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2355                               HWND hwnd, const RECT *lprect )
2356 {
2357     MSG msg;
2358     POPUPMENU *menu;
2359     BOOL fRemove;
2360     INT executedMenuId = 0;
2361     MTRACKER mt = { 0, hmenu, hmenu, hwnd, {x, y} };    /* control struct */
2362
2363     fEndMenu = FALSE;
2364     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
2365
2366     if (wFlags & TPM_BUTTONDOWN) MENU_ButtonDown( &mt, hmenu );
2367
2368     EVENT_Capture( mt.hOwnerWnd, HTMENU );
2369
2370     while (!fEndMenu)
2371     {
2372         menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
2373         msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2374
2375         /* we have to keep the message in the queue until it's
2376          * clear that menu loop is not over yet. */
2377
2378         if (!MSG_InternalGetMessage( &msg, msg.hwnd, mt.hOwnerWnd,
2379                                      MSGF_MENU, PM_NOREMOVE, TRUE )) break;
2380
2381         TranslateMessage( &msg );
2382         mt.pt = msg.pt;
2383
2384         fRemove = FALSE;
2385         if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2386         {
2387             /* Find a menu for this mouse event */
2388             POINT16 pt16;
2389             CONV_POINT32TO16( &msg.pt, &pt16 );
2390             hmenu = MENU_PtMenu( mt.hTopMenu, pt16 );
2391
2392             switch(msg.message)
2393             {
2394                 /* no WM_NC... messages in captured state */
2395
2396                 case WM_RBUTTONDBLCLK:
2397                 case WM_RBUTTONDOWN:
2398                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
2399                     /* fall through */
2400                 case WM_LBUTTONDBLCLK:
2401                 case WM_LBUTTONDOWN:
2402                     fEndMenu |= !MENU_ButtonDown( &mt, hmenu );
2403                     break;
2404                 
2405                 case WM_RBUTTONUP:
2406                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
2407                     /* fall through */
2408                 case WM_LBUTTONUP:
2409                     /* Check if a menu was selected by the mouse */
2410                     if (hmenu)
2411                     {
2412                         executedMenuId = MENU_ButtonUp( &mt, hmenu );
2413
2414                         /* the executedMenuId higher than one means that it contains
2415                          the id of the selected item so we have to put the fEndMenu to TRUE.
2416                          Otherwise, it contains a continue
2417                          flag returned by MENU_ButtonUp indicating if we can continue with
2418                          menu tracking or not*/
2419                         fEndMenu = ((executedMenuId > 1) ? TRUE : FALSE);
2420                         
2421                     }
2422                     /* No menu was selected by the mouse */
2423                     /* if the function was called by TrackPopupMenu, continue
2424                        with the menu tracking. If not, stop it */
2425                     else
2426                         fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2427                     
2428                     break;
2429                 
2430                 case WM_MOUSEMOVE:
2431                     /* In win95 winelook, the selected menu item must be changed every time the
2432                        mouse moves. In Win31 winelook, the mouse button has to be held down */
2433                      
2434                     if ( (TWEAK_WineLook > WIN31_LOOK) ||
2435                          ( (msg.wParam & MK_LBUTTON) ||
2436                            ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2437
2438                         fEndMenu |= !MENU_MouseMove( &mt, hmenu );
2439
2440             } /* switch(msg.message) - mouse */
2441         }
2442         else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2443         {
2444             fRemove = TRUE;  /* Keyboard messages are always removed */
2445             switch(msg.message)
2446             {
2447             case WM_KEYDOWN:
2448                 switch(msg.wParam)
2449                 {
2450                 case VK_HOME:
2451                 case VK_END:
2452                     MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, 
2453                                      NO_SELECTED_ITEM, FALSE );
2454                 /* fall through */
2455                 case VK_UP:
2456                     MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, 
2457                                        (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2458                     break;
2459
2460                 case VK_DOWN: /* If on menu bar, pull-down the menu */
2461
2462                     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
2463                     if (!(menu->wFlags & MF_POPUP))
2464                         mt.hCurrentMenu = MENU_ShowSubPopup( mt.hOwnerWnd, mt.hTopMenu, TRUE );
2465                     else      /* otherwise try to move selection */
2466                         MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2467                     break;
2468
2469                 case VK_LEFT:
2470                     MENU_KeyLeft( &mt );
2471                     break;
2472                     
2473                 case VK_RIGHT:
2474                     MENU_KeyRight( &mt );
2475                     break;
2476                     
2477                 case VK_ESCAPE:
2478                     fEndMenu = TRUE;
2479                     break;
2480
2481                 default:
2482                     break;
2483                 }
2484                 break;  /* WM_KEYDOWN */
2485
2486             case WM_SYSKEYDOWN:
2487                 switch(msg.wParam)
2488                 {
2489                 case VK_MENU:
2490                     fEndMenu = TRUE;
2491                     break;
2492                     
2493                 }
2494                 break;  /* WM_SYSKEYDOWN */
2495
2496             case WM_CHAR:
2497                 {
2498                     UINT        pos;
2499
2500                     if (msg.wParam == '\r' || msg.wParam == ' ')
2501                     {
2502                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu);
2503                         fEndMenu = ((executedMenuId != 0) ? TRUE:FALSE);
2504
2505                         break;
2506                     }
2507
2508                       /* Hack to avoid control chars. */
2509                       /* We will find a better way real soon... */
2510                     if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
2511
2512                     pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu, 
2513                                               LOWORD(msg.wParam), FALSE );
2514                     if (pos == (UINT)-2) fEndMenu = TRUE;
2515                     else if (pos == (UINT)-1) MessageBeep(0);
2516                     else
2517                     {
2518                         MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos, TRUE );
2519                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu);
2520                         fEndMenu = ((executedMenuId != 0) ? TRUE:FALSE);
2521                     }
2522                 }                   
2523                 break;
2524             }  /* switch(msg.message) - kbd */
2525         }
2526         else
2527         {
2528             DispatchMessageA( &msg );
2529         }
2530
2531         if (!fEndMenu) fRemove = TRUE;
2532
2533         /* finally remove message from the queue */
2534
2535         if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2536             PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2537         else mt.trackFlags &= ~TF_SKIPREMOVE;
2538     }
2539
2540     ReleaseCapture();
2541     if( IsWindow( mt.hOwnerWnd ) )
2542     {
2543         MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2544
2545         menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hTopMenu );
2546         if (menu && menu->wFlags & MF_POPUP) 
2547         {
2548             ShowWindow( menu->hWnd, SW_HIDE );
2549             uSubPWndLevel = 0;
2550         }
2551         MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE );
2552         SendMessage16( mt.hOwnerWnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
2553     }
2554
2555     /* returning the id of the selected menu.
2556       The return value is only used by TrackPopupMenu */
2557     return executedMenuId;
2558 }
2559
2560 /***********************************************************************
2561  *           MENU_InitTracking
2562  */
2563 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu)
2564 {
2565     HideCaret(0);
2566     SendMessage16( hWnd, WM_ENTERMENULOOP, 0, 0 );
2567     SendMessage16( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
2568     SendMessage16( hWnd, WM_INITMENU, hMenu, 0 );
2569     return TRUE;
2570 }
2571
2572 /***********************************************************************
2573  *           MENU_TrackMouseMenuBar
2574  *
2575  * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2576  */
2577 void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt )
2578 {
2579     HWND  hWnd = wndPtr->hwndSelf;
2580     HMENU hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
2581
2582     if (IsMenu(hMenu))
2583     {
2584         MENU_InitTracking( hWnd, hMenu );
2585         MENU_TrackMenu( hMenu, TPM_ENTERIDLEEX | TPM_BUTTONDOWN | 
2586                         TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, hWnd, NULL );
2587
2588         SendMessage16( hWnd, WM_EXITMENULOOP, 0, 0 );
2589         ShowCaret(0);
2590     }
2591 }
2592
2593
2594 /***********************************************************************
2595  *           MENU_TrackKbdMenuBar
2596  *
2597  * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2598  */
2599 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
2600 {
2601    UINT uItem = NO_SELECTED_ITEM;
2602    HMENU hTrackMenu; 
2603
2604     /* find window that has a menu */
2605  
2606     while( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwStyle & WS_SYSMENU) )
2607         if( !(wndPtr = wndPtr->parent) ) return;
2608
2609     /* check if we have to track a system menu */
2610           
2611     if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) || 
2612         !wndPtr->wIDmenu || vkey == VK_SPACE )
2613     {
2614         if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
2615         hTrackMenu = wndPtr->hSysMenu;
2616         uItem = 0;
2617         wParam |= HTSYSMENU;    /* prevent item lookup */
2618     }
2619     else
2620         hTrackMenu = wndPtr->wIDmenu;
2621
2622     if (IsMenu( hTrackMenu ))
2623     {
2624         MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu );
2625
2626         if( vkey && vkey != VK_SPACE )
2627         {
2628             uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu, 
2629                                         vkey, (wParam & HTSYSMENU) );
2630             if( uItem >= (UINT)(-2) )
2631             {
2632                 if( uItem == (UINT)(-1) ) MessageBeep(0);
2633                 hTrackMenu = 0;
2634             }
2635         }
2636
2637         if( hTrackMenu )
2638         {
2639             MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE );
2640
2641             if( uItem == NO_SELECTED_ITEM )
2642                 MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
2643             else if( vkey )
2644                 PostMessage16( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
2645
2646             MENU_TrackMenu( hTrackMenu, TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON,
2647                             0, 0, wndPtr->hwndSelf, NULL );
2648         }
2649         SendMessage16( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
2650         ShowCaret(0);
2651     }
2652 }
2653
2654
2655 /**********************************************************************
2656  *           TrackPopupMenu16   (USER.416)
2657  */
2658 BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
2659                            INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
2660 {
2661     RECT r;
2662     if (lpRect)
2663          CONV_RECT16TO32( lpRect, &r );
2664     return TrackPopupMenu( hMenu, wFlags, x, y, nReserved, hWnd,
2665                              lpRect ? &r : NULL );
2666 }
2667
2668
2669 /**********************************************************************
2670  *           TrackPopupMenu32   (USER32.549)
2671  */
2672 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
2673                            INT nReserved, HWND hWnd, const RECT *lpRect )
2674 {
2675     BOOL ret = FALSE;
2676
2677     HideCaret(0);
2678     SendMessage16( hWnd, WM_INITMENUPOPUP, (WPARAM16)hMenu, 0);
2679     if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 )) 
2680         ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
2681     ShowCaret(0);
2682     return ret;
2683 }
2684
2685 /**********************************************************************
2686  *           TrackPopupMenuEx   (USER32.550)
2687  */
2688 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
2689                                 HWND hWnd, LPTPMPARAMS lpTpm )
2690 {
2691     FIXME(menu, "not fully implemented\n" );
2692     return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
2693                              lpTpm ? &lpTpm->rcExclude : NULL );
2694 }
2695
2696 /***********************************************************************
2697  *           PopupMenuWndProc
2698  *
2699  * NOTE: Windows has totally different (and undocumented) popup wndproc.
2700  */
2701 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
2702                                  LPARAM lParam )
2703 {    
2704     WND* wndPtr = WIN_FindWndPtr(hwnd);
2705
2706     switch(message)
2707     {
2708     case WM_CREATE:
2709         {
2710             CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
2711             SetWindowLongA( hwnd, 0, (LONG)cs->lpCreateParams );
2712             return 0;
2713         }
2714
2715     case WM_MOUSEACTIVATE:  /* We don't want to be activated */
2716         return MA_NOACTIVATE;
2717
2718     case WM_PAINT:
2719         {
2720             PAINTSTRUCT ps;
2721             BeginPaint( hwnd, &ps );
2722             MENU_DrawPopupMenu( hwnd, ps.hdc,
2723                                 (HMENU)GetWindowLongA( hwnd, 0 ) );
2724             EndPaint( hwnd, &ps );
2725             return 0;
2726         }
2727     case WM_ERASEBKGND:
2728         return 1;
2729
2730     case WM_DESTROY:
2731
2732         /* zero out global pointer in case resident popup window
2733          * was somehow destroyed. */
2734
2735         if( pTopPopupWnd )
2736         {
2737             if( hwnd == pTopPopupWnd->hwndSelf )
2738             {
2739                 ERR(menu, "resident popup destroyed!\n");
2740
2741                 pTopPopupWnd = NULL;
2742                 uSubPWndLevel = 0;
2743             }
2744             else
2745                 uSubPWndLevel--;
2746         }
2747         break;
2748
2749     case WM_SHOWWINDOW:
2750
2751         if( wParam )
2752         {
2753             if( !(*(HMENU*)wndPtr->wExtra) )
2754                 ERR(menu,"no menu to display\n");
2755         }
2756         else
2757             *(HMENU*)wndPtr->wExtra = 0;
2758         break;
2759
2760     case MM_SETMENUHANDLE:
2761
2762         *(HMENU*)wndPtr->wExtra = (HMENU)wParam;
2763         break;
2764
2765     case MM_GETMENUHANDLE:
2766
2767         return *(HMENU*)wndPtr->wExtra;
2768
2769     default:
2770         return DefWindowProcA( hwnd, message, wParam, lParam );
2771     }
2772     return 0;
2773 }
2774
2775
2776 /***********************************************************************
2777  *           MENU_GetMenuBarHeight
2778  *
2779  * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2780  */
2781 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
2782                               INT orgX, INT orgY )
2783 {
2784     HDC hdc;
2785     RECT rectBar;
2786     WND *wndPtr;
2787     LPPOPUPMENU lppop;
2788
2789     TRACE(menu, "HWND 0x%x, width %d, "
2790                   "at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
2791     
2792     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
2793     if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu)))
2794       return 0;
2795     hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
2796     SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU);
2797     MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
2798     ReleaseDC( hwnd, hdc );
2799     return lppop->Height;
2800 }
2801
2802
2803 /*******************************************************************
2804  *         ChangeMenu16    (USER.153)
2805  */
2806 BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
2807                             UINT16 id, UINT16 flags )
2808 {
2809     TRACE(menu,"menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2810                   hMenu, pos, (DWORD)data, id, flags );
2811     if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
2812                                                 id, data );
2813
2814     /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2815     /* for MF_DELETE. We should check the parameters for all others */
2816     /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2817
2818     if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
2819     if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
2820                                                id, data );
2821     if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
2822                                               flags & MF_BYPOSITION ? pos : id,
2823                                               flags & ~MF_REMOVE );
2824     /* Default: MF_INSERT */
2825     return InsertMenu16( hMenu, pos, flags, id, data );
2826 }
2827
2828
2829 /*******************************************************************
2830  *         ChangeMenu32A    (USER32.23)
2831  */
2832 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
2833                              UINT id, UINT flags )
2834 {
2835     TRACE(menu,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2836                   hMenu, pos, (DWORD)data, id, flags );
2837     if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
2838                                                  id, data );
2839     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
2840     if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
2841                                                 id, data );
2842     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
2843                                               flags & MF_BYPOSITION ? pos : id,
2844                                               flags & ~MF_REMOVE );
2845     /* Default: MF_INSERT */
2846     return InsertMenuA( hMenu, pos, flags, id, data );
2847 }
2848
2849
2850 /*******************************************************************
2851  *         ChangeMenu32W    (USER32.24)
2852  */
2853 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
2854                              UINT id, UINT flags )
2855 {
2856     TRACE(menu,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2857                   hMenu, pos, (DWORD)data, id, flags );
2858     if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
2859                                                  id, data );
2860     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
2861     if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
2862                                                 id, data );
2863     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
2864                                               flags & MF_BYPOSITION ? pos : id,
2865                                               flags & ~MF_REMOVE );
2866     /* Default: MF_INSERT */
2867     return InsertMenuW( hMenu, pos, flags, id, data );
2868 }
2869
2870
2871 /*******************************************************************
2872  *         CheckMenuItem16    (USER.154)
2873  */
2874 BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
2875 {
2876     return (BOOL16)CheckMenuItem( hMenu, id, flags );
2877 }
2878
2879
2880 /*******************************************************************
2881  *         CheckMenuItem32    (USER32.46)
2882  */
2883 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
2884 {
2885     MENUITEM *item;
2886     DWORD ret;
2887
2888     TRACE(menu,"%04x %04x %04x\n", hMenu, id, flags );
2889     if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
2890     ret = item->fState & MF_CHECKED;
2891     if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
2892     else item->fState &= ~MF_CHECKED;
2893     return ret;
2894 }
2895
2896
2897 /**********************************************************************
2898  *         EnableMenuItem16    (USER.155)
2899  */
2900 UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
2901 {
2902     return EnableMenuItem( hMenu, wItemID, wFlags );
2903 }
2904
2905
2906 /**********************************************************************
2907  *         EnableMenuItem32    (USER32.170)
2908  */
2909 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
2910 {
2911     UINT    oldflags;
2912     MENUITEM *item;
2913
2914     TRACE(menu,"(%04x, %04X, %04X) !\n", 
2915                  hMenu, wItemID, wFlags);
2916
2917     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
2918         return (UINT)-1;
2919
2920     oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
2921     item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
2922     return oldflags;
2923 }
2924
2925
2926 /*******************************************************************
2927  *         GetMenuString16    (USER.161)
2928  */
2929 INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
2930                               LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
2931 {
2932     return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
2933 }
2934
2935
2936 /*******************************************************************
2937  *         GetMenuString32A    (USER32.268)
2938  */
2939 INT WINAPI GetMenuStringA( HMENU hMenu, UINT wItemID,
2940                                LPSTR str, INT nMaxSiz, UINT wFlags )
2941 {
2942     MENUITEM *item;
2943
2944     TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2945                  hMenu, wItemID, str, nMaxSiz, wFlags );
2946     if (!str || !nMaxSiz) return 0;
2947     str[0] = '\0';
2948     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
2949     if (!IS_STRING_ITEM(item->fType)) return 0;
2950     lstrcpynA( str, item->text, nMaxSiz );
2951     TRACE(menu, "returning '%s'\n", str );
2952     return strlen(str);
2953 }
2954
2955
2956 /*******************************************************************
2957  *         GetMenuString32W    (USER32.269)
2958  */
2959 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
2960                                LPWSTR str, INT nMaxSiz, UINT wFlags )
2961 {
2962     MENUITEM *item;
2963
2964     TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2965                  hMenu, wItemID, str, nMaxSiz, wFlags );
2966     if (!str || !nMaxSiz) return 0;
2967     str[0] = '\0';
2968     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
2969     if (!IS_STRING_ITEM(item->fType)) return 0;
2970     lstrcpynAtoW( str, item->text, nMaxSiz );
2971     return lstrlenW(str);
2972 }
2973
2974
2975 /**********************************************************************
2976  *         HiliteMenuItem16    (USER.162)
2977  */
2978 BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
2979                                 UINT16 wHilite )
2980 {
2981     return HiliteMenuItem( hWnd, hMenu, wItemID, wHilite );
2982 }
2983
2984
2985 /**********************************************************************
2986  *         HiliteMenuItem32    (USER32.318)
2987  */
2988 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
2989                                 UINT wHilite )
2990 {
2991     LPPOPUPMENU menu;
2992     TRACE(menu,"(%04x, %04x, %04x, %04x);\n", 
2993                  hWnd, hMenu, wItemID, wHilite);
2994     if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
2995     if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
2996     if (menu->FocusedItem == wItemID) return TRUE;
2997     MENU_HideSubPopups( hWnd, hMenu, FALSE );
2998     MENU_SelectItem( hWnd, hMenu, wItemID, TRUE );
2999     return TRUE;
3000 }
3001
3002
3003 /**********************************************************************
3004  *         GetMenuState16    (USER.250)
3005  */
3006 UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
3007 {
3008     return GetMenuState( hMenu, wItemID, wFlags );
3009 }
3010
3011
3012 /**********************************************************************
3013  *         GetMenuState32    (USER32.267)
3014  */
3015 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3016 {
3017     MENUITEM *item;
3018     TRACE(menu,"(%04x, %04x, %04x);\n", 
3019                  hMenu, wItemID, wFlags);
3020     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3021     debug_print_menuitem ("  item: ", item, "");
3022     if (item->fType & MF_POPUP)
3023     {
3024         POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( item->hSubMenu );
3025         if (!menu) return -1;
3026         else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3027     }
3028     else
3029     {
3030         /* We used to (from way back then) mask the result to 0xff.  */
3031         /* I don't know why and it seems wrong as the documented */
3032         /* return flag MF_SEPARATOR is outside that mask.  */
3033         return (item->fType | item->fState);
3034     }
3035 }
3036
3037
3038 /**********************************************************************
3039  *         GetMenuItemCount16    (USER.263)
3040  */
3041 INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
3042 {
3043     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3044     if (!IS_A_MENU(menu)) return -1;
3045     TRACE(menu,"(%04x) returning %d\n", 
3046                   hMenu, menu->nItems );
3047     return menu->nItems;
3048 }
3049
3050
3051 /**********************************************************************
3052  *         GetMenuItemCount32    (USER32.262)
3053  */
3054 INT WINAPI GetMenuItemCount( HMENU hMenu )
3055 {
3056     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3057     if (!IS_A_MENU(menu)) return -1;
3058     TRACE(menu,"(%04x) returning %d\n", 
3059                   hMenu, menu->nItems );
3060     return menu->nItems;
3061 }
3062
3063
3064 /**********************************************************************
3065  *         GetMenuItemID16    (USER.264)
3066  */
3067 UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3068 {
3069     LPPOPUPMENU menu;
3070
3071     if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
3072     if ((nPos < 0) || ((UINT16) nPos >= menu->nItems)) return -1;
3073     if (menu->items[nPos].fType & MF_POPUP) return -1;
3074     return menu->items[nPos].wID;
3075 }
3076
3077
3078 /**********************************************************************
3079  *         GetMenuItemID32    (USER32.263)
3080  */
3081 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3082 {
3083     LPPOPUPMENU menu;
3084
3085     if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
3086     if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
3087     if (menu->items[nPos].fType & MF_POPUP) return -1; 
3088     return menu->items[nPos].wID;
3089 }
3090
3091
3092 /*******************************************************************
3093  *         InsertMenu16    (USER.410)
3094  */
3095 BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3096                             UINT16 id, SEGPTR data )
3097 {
3098     UINT pos32 = (UINT)pos;
3099     if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
3100     if (IS_STRING_ITEM(flags) && data)
3101         return InsertMenuA( hMenu, pos32, flags, id,
3102                               (LPSTR)PTR_SEG_TO_LIN(data) );
3103     return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
3104 }
3105
3106
3107 /*******************************************************************
3108  *         InsertMenu32A    (USER32.322)
3109  */
3110 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3111                              UINT id, LPCSTR str )
3112 {
3113     MENUITEM *item;
3114
3115     if (IS_STRING_ITEM(flags) && str)
3116         TRACE(menu, "hMenu %04x, pos %d, flags %08x, "
3117                       "id %04x, str '%s'\n",
3118                       hMenu, pos, flags, id, str );
3119     else TRACE(menu, "hMenu %04x, pos %d, flags %08x, "
3120                        "id %04x, str %08lx (not a string)\n",
3121                        hMenu, pos, flags, id, (DWORD)str );
3122
3123     if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3124
3125     if (!(MENU_SetItemData( item, flags, id, str )))
3126     {
3127         RemoveMenu( hMenu, pos, flags );
3128         return FALSE;
3129     }
3130
3131     if (flags & MF_POPUP)  /* Set the MF_POPUP flag on the popup-menu */
3132         ((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU16)id))->wFlags |= MF_POPUP;
3133
3134     item->hCheckBit = item->hUnCheckBit = 0;
3135     return TRUE;
3136 }
3137
3138
3139 /*******************************************************************
3140  *         InsertMenu32W    (USER32.325)
3141  */
3142 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3143                              UINT id, LPCWSTR str )
3144 {
3145     BOOL ret;
3146
3147     if (IS_STRING_ITEM(flags) && str)
3148     {
3149         LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3150         ret = InsertMenuA( hMenu, pos, flags, id, newstr );
3151         HeapFree( GetProcessHeap(), 0, newstr );
3152         return ret;
3153     }
3154     else return InsertMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3155 }
3156
3157
3158 /*******************************************************************
3159  *         AppendMenu16    (USER.411)
3160  */
3161 BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
3162 {
3163     return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3164 }
3165
3166
3167 /*******************************************************************
3168  *         AppendMenu32A    (USER32.5)
3169  */
3170 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3171                              UINT id, LPCSTR data )
3172 {
3173     return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3174 }
3175
3176
3177 /*******************************************************************
3178  *         AppendMenu32W    (USER32.6)
3179  */
3180 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3181                              UINT id, LPCWSTR data )
3182 {
3183     return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3184 }
3185
3186
3187 /**********************************************************************
3188  *         RemoveMenu16    (USER.412)
3189  */
3190 BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3191 {
3192     return RemoveMenu( hMenu, nPos, wFlags );
3193 }
3194
3195
3196 /**********************************************************************
3197  *         RemoveMenu32    (USER32.441)
3198  */
3199 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3200 {
3201     LPPOPUPMENU menu;
3202     MENUITEM *item;
3203
3204     TRACE(menu,"(%04x, %04x, %04x)\n",hMenu, nPos, wFlags);
3205     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3206     if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
3207     
3208       /* Remove item */
3209
3210     MENU_FreeItemData( item );
3211
3212     if (--menu->nItems == 0)
3213     {
3214         HeapFree( SystemHeap, 0, menu->items );
3215         menu->items = NULL;
3216     }
3217     else
3218     {
3219         while(nPos < menu->nItems)
3220         {
3221             *item = *(item+1);
3222             item++;
3223             nPos++;
3224         }
3225         menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
3226                                    menu->nItems * sizeof(MENUITEM) );
3227     }
3228     return TRUE;
3229 }
3230
3231
3232 /**********************************************************************
3233  *         DeleteMenu16    (USER.413)
3234  */
3235 BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
3236 {
3237     return DeleteMenu( hMenu, nPos, wFlags );
3238 }
3239
3240
3241 /**********************************************************************
3242  *         DeleteMenu32    (USER32.129)
3243  */
3244 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3245 {
3246     MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3247     if (!item) return FALSE;
3248     if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3249       /* nPos is now the position of the item */
3250     RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3251     return TRUE;
3252 }
3253
3254
3255 /*******************************************************************
3256  *         ModifyMenu16    (USER.414)
3257  */
3258 BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3259                             UINT16 id, SEGPTR data )
3260 {
3261     if (IS_STRING_ITEM(flags))
3262         return ModifyMenuA( hMenu, pos, flags, id,
3263                               (LPSTR)PTR_SEG_TO_LIN(data) );
3264     return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
3265 }
3266
3267
3268 /*******************************************************************
3269  *         ModifyMenu32A    (USER32.397)
3270  */
3271 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3272                              UINT id, LPCSTR str )
3273 {
3274     MENUITEM *item;
3275
3276     if (IS_STRING_ITEM(flags))
3277     {
3278         TRACE(menu, "%04x %d %04x %04x '%s'\n",
3279                       hMenu, pos, flags, id, str ? str : "#NULL#" );
3280         if (!str) return FALSE;
3281     }
3282     else
3283     {
3284         TRACE(menu, "%04x %d %04x %04x %08lx\n",
3285                       hMenu, pos, flags, id, (DWORD)str );
3286     }
3287
3288     if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3289     return MENU_SetItemData( item, flags, id, str );
3290 }
3291
3292
3293 /*******************************************************************
3294  *         ModifyMenu32W    (USER32.398)
3295  */
3296 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3297                              UINT id, LPCWSTR str )
3298 {
3299     BOOL ret;
3300
3301     if (IS_STRING_ITEM(flags) && str)
3302     {
3303         LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
3304         ret = ModifyMenuA( hMenu, pos, flags, id, newstr );
3305         HeapFree( GetProcessHeap(), 0, newstr );
3306         return ret;
3307     }
3308     else return ModifyMenuA( hMenu, pos, flags, id, (LPCSTR)str );
3309 }
3310
3311
3312 /**********************************************************************
3313  *         CreatePopupMenu16    (USER.415)
3314  */
3315 HMENU16 WINAPI CreatePopupMenu16(void)
3316 {
3317     return CreatePopupMenu();
3318 }
3319
3320
3321 /**********************************************************************
3322  *         CreatePopupMenu32    (USER32.82)
3323  */
3324 HMENU WINAPI CreatePopupMenu(void)
3325 {
3326     HMENU hmenu;
3327     POPUPMENU *menu;
3328
3329     if (!(hmenu = CreateMenu())) return 0;
3330     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
3331     menu->wFlags |= MF_POPUP;
3332     return hmenu;
3333 }
3334
3335
3336 /**********************************************************************
3337  *         GetMenuCheckMarkDimensions    (USER.417) (USER32.258)
3338  */
3339 DWORD WINAPI GetMenuCheckMarkDimensions(void)
3340 {
3341     return MAKELONG( check_bitmap_width, check_bitmap_height );
3342 }
3343
3344
3345 /**********************************************************************
3346  *         SetMenuItemBitmaps16    (USER.418)
3347  */
3348 BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3349                                     HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
3350 {
3351     return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
3352 }
3353
3354
3355 /**********************************************************************
3356  *         SetMenuItemBitmaps32    (USER32.490)
3357  */
3358 BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3359                                     HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3360 {
3361     MENUITEM *item;
3362     TRACE(menu,"(%04x, %04x, %04x, %04x, %04x)\n",
3363                  hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3364     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3365
3366     if (!hNewCheck && !hNewUnCheck)
3367     {
3368         item->fState &= ~MF_USECHECKBITMAPS;
3369     }
3370     else  /* Install new bitmaps */
3371     {
3372         item->hCheckBit = hNewCheck;
3373         item->hUnCheckBit = hNewUnCheck;
3374         item->fState |= MF_USECHECKBITMAPS;
3375     }
3376     return TRUE;
3377 }
3378
3379
3380 /**********************************************************************
3381  *         CreateMenu16    (USER.151)
3382  */
3383 HMENU16 WINAPI CreateMenu16(void)
3384 {
3385     return CreateMenu();
3386 }
3387
3388
3389 /**********************************************************************
3390  *         CreateMenu32    (USER32.81)
3391  */
3392 HMENU WINAPI CreateMenu(void)
3393 {
3394     HMENU hMenu;
3395     LPPOPUPMENU menu;
3396     if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3397     menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3398     menu->wFlags = 0;
3399     menu->wMagic = MENU_MAGIC;
3400     menu->hTaskQ = 0;
3401     menu->Width  = 0;
3402     menu->Height = 0;
3403     menu->nItems = 0;
3404     menu->hWnd   = 0;
3405     menu->items  = NULL;
3406     menu->FocusedItem = NO_SELECTED_ITEM;
3407     TRACE(menu, "return %04x\n", hMenu );
3408     return hMenu;
3409 }
3410
3411
3412 /**********************************************************************
3413  *         DestroyMenu16    (USER.152)
3414  */
3415 BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
3416 {
3417     return DestroyMenu( hMenu );
3418 }
3419
3420
3421 /**********************************************************************
3422  *         DestroyMenu32    (USER32.134)
3423  */
3424 BOOL WINAPI DestroyMenu( HMENU hMenu )
3425 {
3426     TRACE(menu,"(%04x)\n", hMenu);
3427
3428     /* Silently ignore attempts to destroy default system popup */
3429
3430     if (hMenu && hMenu != MENU_DefSysPopup)
3431     {
3432         LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3433
3434         if( pTopPopupWnd && (hMenu == *(HMENU*)pTopPopupWnd->wExtra) )
3435           *(UINT*)pTopPopupWnd->wExtra = 0;
3436
3437         if (IS_A_MENU( lppop ))
3438         {
3439             lppop->wMagic = 0;  /* Mark it as destroyed */
3440
3441             if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
3442                 (!pTopPopupWnd || (lppop->hWnd != pTopPopupWnd->hwndSelf)))
3443                 DestroyWindow( lppop->hWnd );
3444
3445             if (lppop->items)   /* recursively destroy submenus */
3446             {
3447                 int i;
3448                 MENUITEM *item = lppop->items;
3449                 for (i = lppop->nItems; i > 0; i--, item++)
3450                 {
3451                     if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3452                     MENU_FreeItemData( item );
3453                 }
3454                 HeapFree( SystemHeap, 0, lppop->items );
3455             }
3456             USER_HEAP_FREE( hMenu );
3457         }
3458         else return FALSE;
3459     }
3460     return (hMenu != MENU_DefSysPopup);
3461 }
3462
3463
3464 /**********************************************************************
3465  *         GetSystemMenu16    (USER.156)
3466  */
3467 HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
3468 {
3469     return GetSystemMenu( hWnd, bRevert );
3470 }
3471
3472
3473 /**********************************************************************
3474  *         GetSystemMenu32    (USER32.291)
3475  */
3476 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3477 {
3478     WND *wndPtr = WIN_FindWndPtr( hWnd );
3479
3480     if (wndPtr)
3481     {
3482         if( wndPtr->hSysMenu )
3483         {
3484             if( bRevert )
3485             {
3486                 DestroyMenu(wndPtr->hSysMenu); 
3487                 wndPtr->hSysMenu = 0;
3488             }
3489             else
3490             {
3491                 POPUPMENU *menu = (POPUPMENU*) 
3492                            USER_HEAP_LIN_ADDR(wndPtr->hSysMenu);
3493                 if( menu->items[0].hSubMenu == MENU_DefSysPopup )
3494                     menu->items[0].hSubMenu = MENU_CopySysPopup();
3495             }
3496         }
3497
3498         if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3499             wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3500
3501         if( wndPtr->hSysMenu )
3502             return GetSubMenu16(wndPtr->hSysMenu, 0);
3503     }
3504     return 0;
3505 }
3506
3507
3508 /*******************************************************************
3509  *         SetSystemMenu16    (USER.280)
3510  */
3511 BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
3512 {
3513     return SetSystemMenu( hwnd, hMenu );
3514 }
3515
3516
3517 /*******************************************************************
3518  *         SetSystemMenu32    (USER32.508)
3519  */
3520 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3521 {
3522     WND *wndPtr = WIN_FindWndPtr(hwnd);
3523
3524     if (wndPtr)
3525     {
3526         if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3527         wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3528         return TRUE;
3529     }
3530     return FALSE;
3531 }
3532
3533
3534 /**********************************************************************
3535  *         GetMenu16    (USER.157)
3536  */
3537 HMENU16 WINAPI GetMenu16( HWND16 hWnd ) 
3538 {
3539     WND * wndPtr = WIN_FindWndPtr(hWnd);
3540     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) 
3541         return (HMENU16)wndPtr->wIDmenu;
3542     return 0;
3543 }
3544
3545
3546 /**********************************************************************
3547  *         GetMenu32    (USER32.257)
3548  */
3549 HMENU WINAPI GetMenu( HWND hWnd ) 
3550
3551     WND * wndPtr = WIN_FindWndPtr(hWnd);
3552     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) 
3553         return (HMENU)wndPtr->wIDmenu;
3554     return 0;
3555 }
3556
3557
3558 /**********************************************************************
3559  *         SetMenu16    (USER.158)
3560  */
3561 BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
3562 {
3563     return SetMenu( hWnd, hMenu );
3564 }
3565
3566
3567 /**********************************************************************
3568  *         SetMenu32    (USER32.487)
3569  */
3570 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
3571 {
3572     WND * wndPtr = WIN_FindWndPtr(hWnd);
3573
3574     TRACE(menu,"(%04x, %04x);\n", hWnd, hMenu);
3575
3576     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
3577     {
3578         if (GetCapture() == hWnd) ReleaseCapture();
3579
3580         wndPtr->wIDmenu = (UINT)hMenu;
3581         if (hMenu != 0)
3582         {
3583             LPPOPUPMENU lpmenu;
3584
3585             if (!(lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
3586             lpmenu->hWnd = hWnd;
3587             lpmenu->wFlags &= ~MF_POPUP;  /* Can't be a popup */
3588             lpmenu->Height = 0;  /* Make sure we recalculate the size */
3589         }
3590         if (IsWindowVisible(hWnd))
3591             SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3592                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3593         return TRUE;
3594     }
3595     return FALSE;
3596 }
3597
3598
3599
3600 /**********************************************************************
3601  *         GetSubMenu16    (USER.159)
3602  */
3603 HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
3604 {
3605     return GetSubMenu( hMenu, nPos );
3606 }
3607
3608
3609 /**********************************************************************
3610  *         GetSubMenu32    (USER32.288)
3611  */
3612 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
3613 {
3614     LPPOPUPMENU lppop;
3615
3616     if (!(lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return 0;
3617     if ((UINT)nPos >= lppop->nItems) return 0;
3618     if (!(lppop->items[nPos].fType & MF_POPUP)) return 0;
3619     return lppop->items[nPos].hSubMenu;
3620 }
3621
3622
3623 /**********************************************************************
3624  *         DrawMenuBar16    (USER.160)
3625  */
3626 void WINAPI DrawMenuBar16( HWND16 hWnd )
3627 {
3628     DrawMenuBar( hWnd );
3629 }
3630
3631
3632 /**********************************************************************
3633  *         DrawMenuBar32    (USER32.161)
3634  */
3635 BOOL WINAPI DrawMenuBar( HWND hWnd )
3636 {
3637     LPPOPUPMENU lppop;
3638     WND *wndPtr = WIN_FindWndPtr(hWnd);
3639     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
3640     {
3641         lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu);
3642         if (lppop == NULL) return FALSE;
3643
3644         lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
3645         SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3646                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3647         return TRUE;
3648     }
3649     return FALSE;
3650 }
3651
3652
3653 /***********************************************************************
3654  *           EndMenu   (USER.187) (USER32.175)
3655  */
3656 void WINAPI EndMenu(void)
3657 {
3658     fEndMenu = TRUE;
3659 }
3660
3661
3662 /***********************************************************************
3663  *           LookupMenuHandle   (USER.217)
3664  */
3665 HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
3666 {
3667     HMENU hmenu32 = hmenu;
3668     UINT id32 = id;
3669     if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
3670     else return hmenu32;
3671 }
3672
3673
3674 /**********************************************************************
3675  *          LoadMenu16    (USER.150)
3676  */
3677 HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, SEGPTR name )
3678 {
3679     HRSRC16 hRsrc;
3680     HGLOBAL16 handle;
3681     HMENU16 hMenu;
3682
3683     if (HIWORD(name))
3684     {
3685         char *str = (char *)PTR_SEG_TO_LIN( name );
3686         TRACE(menu, "(%04x,'%s')\n", instance, str );
3687         if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
3688     }
3689     else
3690         TRACE(resource,"(%04x,%04x)\n",instance,LOWORD(name));
3691
3692     if (!name) return 0;
3693     
3694     /* check for Win32 module */
3695     if (HIWORD(instance))
3696         return LoadMenuA(instance,PTR_SEG_TO_LIN(name));
3697     instance = GetExePtr( instance );
3698
3699     if (!(hRsrc = FindResource16( instance, name, RT_MENU16 ))) return 0;
3700     if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
3701     hMenu = LoadMenuIndirect16(LockResource16(handle));
3702     FreeResource16( handle );
3703     return hMenu;
3704 }
3705
3706
3707 /*****************************************************************
3708  *        LoadMenu32A   (USER32.370)
3709  */
3710 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
3711 {
3712     HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
3713     if (!hrsrc) return 0;
3714     return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
3715 }
3716
3717
3718 /*****************************************************************
3719  *        LoadMenu32W   (USER32.373)
3720  */
3721 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
3722 {
3723     HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
3724     if (!hrsrc) return 0;
3725     return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
3726 }
3727
3728
3729 /**********************************************************************
3730  *          LoadMenuIndirect16    (USER.220)
3731  */
3732 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
3733 {
3734     HMENU16 hMenu;
3735     WORD version, offset;
3736     LPCSTR p = (LPCSTR)template;
3737
3738     TRACE(menu,"(%p)\n", template );
3739     version = GET_WORD(p);
3740     p += sizeof(WORD);
3741     if (version)
3742     {
3743         WARN(menu, "version must be 0 for Win16\n" );
3744         return 0;
3745     }
3746     offset = GET_WORD(p);
3747     p += sizeof(WORD) + offset;
3748     if (!(hMenu = CreateMenu())) return 0;
3749     if (!MENU_ParseResource( p, hMenu, FALSE ))
3750     {
3751         DestroyMenu( hMenu );
3752         return 0;
3753     }
3754     return hMenu;
3755 }
3756
3757
3758 /**********************************************************************
3759  *          LoadMenuIndirect32A    (USER32.371)
3760  */
3761 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
3762 {
3763     HMENU16 hMenu;
3764     WORD version, offset;
3765     LPCSTR p = (LPCSTR)template;
3766
3767     TRACE(menu,"%p\n", template );
3768     version = GET_WORD(p);
3769     p += sizeof(WORD);
3770     switch (version)
3771       {
3772       case 0:
3773         offset = GET_WORD(p);
3774         p += sizeof(WORD) + offset;
3775         if (!(hMenu = CreateMenu())) return 0;
3776         if (!MENU_ParseResource( p, hMenu, TRUE ))
3777           {
3778             DestroyMenu( hMenu );
3779             return 0;
3780           }
3781         return hMenu;
3782       case 1:
3783         offset = GET_WORD(p);
3784         p += sizeof(WORD) + offset;
3785         if (!(hMenu = CreateMenu())) return 0;
3786         if (!MENUEX_ParseResource( p, hMenu))
3787           {
3788             DestroyMenu( hMenu );
3789             return 0;
3790           }
3791         return hMenu;
3792       default:
3793         ERR(menu, "version %d not supported.\n", version);
3794         return 0;
3795       }
3796 }
3797
3798
3799 /**********************************************************************
3800  *          LoadMenuIndirect32W    (USER32.372)
3801  */
3802 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
3803 {
3804     /* FIXME: is there anything different between A and W? */
3805     return LoadMenuIndirectA( template );
3806 }
3807
3808
3809 /**********************************************************************
3810  *              IsMenu16    (USER.358)
3811  */
3812 BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
3813 {
3814     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
3815     return IS_A_MENU(menu);
3816 }
3817
3818
3819 /**********************************************************************
3820  *              IsMenu32    (USER32.346)
3821  */
3822 BOOL WINAPI IsMenu(HMENU hmenu)
3823 {
3824     LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
3825     return IS_A_MENU(menu);
3826 }
3827
3828 /**********************************************************************
3829  *              GetMenuItemInfo32_common
3830  */
3831
3832 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item,
3833                                          BOOL bypos,
3834                                          LPMENUITEMINFOA lpmii,
3835                                          BOOL unicode)
3836 {
3837   MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
3838     debug_print_menuitem("GetMenuItemInfo32_common: ", menu, "");
3839     if (!menu)
3840         return FALSE;
3841
3842     if (lpmii->fMask & MIIM_TYPE) {
3843         lpmii->fType = menu->fType;
3844         switch (MENU_ITEM_TYPE(menu->fType)) {
3845         case MF_STRING:
3846             if (menu->text && lpmii->dwTypeData && lpmii->cch) {
3847           if (unicode)
3848                     lstrcpynAtoW((LPWSTR) lpmii->dwTypeData,
3849                                  menu->text,
3850                                  lpmii->cch);
3851                 else
3852                     lstrcpynA(lpmii->dwTypeData,
3853                                 menu->text,
3854                                 lpmii->cch);
3855         }
3856             break;
3857         case MF_OWNERDRAW:
3858         case MF_BITMAP:
3859             lpmii->dwTypeData = menu->text;
3860             break;
3861         default:
3862             break;
3863     }
3864     }
3865     if (lpmii->fMask & MIIM_STATE)
3866         lpmii->fState = menu->fState;
3867
3868     if (lpmii->fMask & MIIM_ID)
3869         lpmii->wID = menu->wID;
3870
3871     if (lpmii->fMask & MIIM_SUBMENU)
3872         lpmii->hSubMenu = menu->hSubMenu;
3873
3874     if (lpmii->fMask & MIIM_CHECKMARKS) {
3875         lpmii->hbmpChecked = menu->hCheckBit;
3876         lpmii->hbmpUnchecked = menu->hUnCheckBit;
3877     }
3878     if (lpmii->fMask & MIIM_DATA)
3879         lpmii->dwItemData = menu->dwItemData;
3880
3881   return TRUE;
3882 }
3883
3884 /**********************************************************************
3885  *              GetMenuItemInfo32A    (USER32.264)
3886  */
3887 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
3888                                   LPMENUITEMINFOA lpmii)
3889 {
3890     return GetMenuItemInfo_common (hmenu, item, bypos, lpmii, FALSE);
3891 }
3892
3893 /**********************************************************************
3894  *              GetMenuItemInfo32W    (USER32.265)
3895  */
3896 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
3897                                   LPMENUITEMINFOW lpmii)
3898 {
3899     return GetMenuItemInfo_common (hmenu, item, bypos,
3900                                      (LPMENUITEMINFOA)lpmii, TRUE);
3901 }
3902
3903 /**********************************************************************
3904  *              SetMenuItemInfo32_common
3905  */
3906
3907 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
3908                                        const MENUITEMINFOA *lpmii,
3909                                        BOOL unicode)
3910 {
3911     if (!menu) return FALSE;
3912
3913     if (lpmii->fMask & MIIM_TYPE) {
3914         /* Get rid of old string.  */
3915         if (IS_STRING_ITEM(menu->fType) && menu->text)
3916             HeapFree(SystemHeap, 0, menu->text);
3917
3918         menu->fType = lpmii->fType;
3919         menu->text = lpmii->dwTypeData;
3920         if (IS_STRING_ITEM(menu->fType) && menu->text) {
3921             menu->text =
3922                 unicode
3923                 ? HEAP_strdupWtoA(SystemHeap, 0,
3924                                   (LPWSTR) lpmii->dwTypeData)
3925                 : HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
3926         }
3927     }
3928     if (lpmii->fMask & MIIM_STATE)
3929         menu->fState = lpmii->fState;
3930
3931     if (lpmii->fMask & MIIM_ID)
3932         menu->wID = lpmii->wID;
3933
3934     if (lpmii->fMask & MIIM_SUBMENU) {
3935         menu->hSubMenu = lpmii->hSubMenu;
3936         if (menu->hSubMenu) {
3937             POPUPMENU *subMenu = (POPUPMENU *)USER_HEAP_LIN_ADDR((UINT16)menu->hSubMenu);
3938             if (IS_A_MENU(subMenu)) {
3939                 subMenu->wFlags |= MF_POPUP;
3940                 menu->fType |= MF_POPUP;
3941             }
3942             else
3943                 /* FIXME: Return an error ? */
3944                 menu->fType &= ~MF_POPUP;
3945         }
3946         else
3947             menu->fType &= ~MF_POPUP;
3948     }
3949
3950     if (lpmii->fMask & MIIM_CHECKMARKS)
3951     {
3952         menu->hCheckBit = lpmii->hbmpChecked;
3953         menu->hUnCheckBit = lpmii->hbmpUnchecked;
3954     }
3955     if (lpmii->fMask & MIIM_DATA)
3956         menu->dwItemData = lpmii->dwItemData;
3957
3958     debug_print_menuitem("SetMenuItemInfo32_common: ", menu, "");
3959     return TRUE;
3960 }
3961
3962 /**********************************************************************
3963  *              SetMenuItemInfo32A    (USER32.491)
3964  */
3965 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
3966                                  const MENUITEMINFOA *lpmii) 
3967 {
3968     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
3969                                     lpmii, FALSE);
3970 }
3971
3972 /**********************************************************************
3973  *              SetMenuItemInfo32W    (USER32.492)
3974  */
3975 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
3976                                  const MENUITEMINFOW *lpmii)
3977 {
3978     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
3979                                     (const MENUITEMINFOA*)lpmii, TRUE);
3980 }
3981
3982 /**********************************************************************
3983  *              SetMenuDefaultItem32    (USER32.489)
3984  */
3985 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT item, UINT bypos)
3986 {
3987     MENUITEM *menuitem = MENU_FindItem(&hmenu, &item, bypos);
3988     POPUPMENU *menu;
3989
3990     if (!menuitem) return FALSE;
3991     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hmenu))) return FALSE;
3992
3993     menu->defitem = item; /* position */
3994
3995     debug_print_menuitem("SetMenuDefaultItem32: ", menuitem, "");
3996     FIXME(menu, "(0x%x,%d,%d), empty stub!\n",
3997                   hmenu, item, bypos);
3998     return TRUE;
3999 }
4000
4001 /**********************************************************************
4002  *              GetMenuDefaultItem32    (USER32.260)
4003  */
4004 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4005 {
4006     POPUPMENU *menu;
4007
4008     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hmenu)))
4009         return -1;
4010
4011     FIXME(menu, "(0x%x,%d,%d), stub!\n", hmenu, bypos, flags);
4012     if (bypos & MF_BYPOSITION)
4013         return menu->defitem;
4014     else {
4015         FIXME (menu, "default item 0x%x\n", menu->defitem);
4016         if ((menu->defitem > 0) && (menu->defitem < menu->nItems))
4017             return menu->items[menu->defitem].wID;
4018     }
4019     return -1;
4020 }
4021
4022 /*******************************************************************
4023  *              InsertMenuItem16   (USER.441)
4024  *
4025  * FIXME: untested
4026  */
4027 BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4028                                 const MENUITEMINFO16 *mii )
4029 {
4030     MENUITEMINFOA miia;
4031
4032     miia.cbSize        = sizeof(miia);
4033     miia.fMask         = mii->fMask;
4034     miia.dwTypeData    = mii->dwTypeData;
4035     miia.fType         = mii->fType;
4036     miia.fState        = mii->fState;
4037     miia.wID           = mii->wID;
4038     miia.hSubMenu      = mii->hSubMenu;
4039     miia.hbmpChecked   = mii->hbmpChecked;
4040     miia.hbmpUnchecked = mii->hbmpUnchecked;
4041     miia.dwItemData    = mii->dwItemData;
4042     miia.cch           = mii->cch;
4043     if (IS_STRING_ITEM(miia.fType))
4044         miia.dwTypeData = PTR_SEG_TO_LIN(miia.dwTypeData);
4045     return InsertMenuItemA( hmenu, pos, byposition, &miia );
4046 }
4047
4048
4049 /**********************************************************************
4050  *              InsertMenuItem32A    (USER32.323)
4051  */
4052 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4053                                 const MENUITEMINFOA *lpmii)
4054 {
4055     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4056     return SetMenuItemInfo_common(item, lpmii, FALSE);
4057 }
4058
4059
4060 /**********************************************************************
4061  *              InsertMenuItem32W    (USER32.324)
4062  */
4063 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4064                                 const MENUITEMINFOW *lpmii)
4065 {
4066     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4067     return SetMenuItemInfo_common(item, (const MENUITEMINFOA*)lpmii, TRUE);
4068 }
4069
4070 /**********************************************************************
4071  *              CheckMenuRadioItem32    (USER32.47)
4072  */
4073
4074 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4075                                    UINT first, UINT last, UINT check,
4076                                    UINT bypos)
4077 {
4078      MENUITEM *mifirst, *milast, *micheck;
4079      HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4080
4081      TRACE(menu, "ox%x: %d-%d, check %d, bypos=%d\n",
4082                   hMenu, first, last, check, bypos);
4083
4084      mifirst = MENU_FindItem (&mfirst, &first, bypos);
4085      milast = MENU_FindItem (&mlast, &last, bypos);
4086      micheck = MENU_FindItem (&mcheck, &check, bypos);
4087
4088      if (mifirst == NULL || milast == NULL || micheck == NULL ||
4089          mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4090          micheck > milast || micheck < mifirst)
4091           return FALSE;
4092
4093      while (mifirst <= milast)
4094      {
4095           if (mifirst == micheck)
4096           {
4097                mifirst->fType |= MFT_RADIOCHECK;
4098                mifirst->fState |= MFS_CHECKED;
4099           } else {
4100                mifirst->fType &= ~MFT_RADIOCHECK;
4101                mifirst->fState &= ~MFS_CHECKED;
4102           }
4103           mifirst++;
4104      }
4105
4106      return TRUE;
4107 }
4108
4109 /**********************************************************************
4110  *              CheckMenuRadioItem16    (not a Windows API)
4111  */
4112
4113 BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4114                                    UINT16 first, UINT16 last, UINT16 check,
4115                                    BOOL16 bypos)
4116 {
4117      return CheckMenuRadioItem (hMenu, first, last, check, bypos);
4118 }
4119
4120 /**********************************************************************
4121  *              GetMenuItemRect32    (USER32.266)
4122  *
4123  *      ATTENTION: Here, the returned values in rect are the screen 
4124  *                 coordinates of the item just like if the menu was 
4125  *                 always on the upper left side of the application.
4126  *                 
4127  */
4128 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4129                                  LPRECT rect)
4130 {
4131      POPUPMENU *itemMenu;
4132      MENUITEM *item;
4133      HWND referenceHwnd;
4134
4135      TRACE(menu, "(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4136
4137      item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4138      referenceHwnd = hwnd;
4139
4140      if(!hwnd)
4141      {
4142          itemMenu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
4143          if (itemMenu == NULL) 
4144              return FALSE;
4145
4146          if(itemMenu->hWnd == NULL)
4147              return FALSE;
4148          referenceHwnd = itemMenu->hWnd;
4149      }
4150
4151      if ((rect == NULL) || (item == NULL)) 
4152          return FALSE;
4153
4154      *rect = item->rect;
4155
4156      MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4157
4158      return TRUE;
4159 }
4160
4161 /**********************************************************************
4162  *              GetMenuItemRect16    (USER.665)
4163  */
4164
4165 BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
4166                                  LPRECT16 rect)
4167 {
4168      RECT r32;
4169      BOOL res;
4170
4171      if (!rect) return FALSE;
4172      res = GetMenuItemRect (hwnd, hMenu, uItem, &r32);
4173      CONV_RECT32TO16 (&r32, rect);
4174      return res;
4175 }
4176
4177 /**********************************************************************
4178  *         SetMenuContextHelpId16    (USER.384)
4179  */
4180 BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpId)
4181 {
4182         return SetMenuContextHelpId( hMenu, dwContextHelpId );
4183 }
4184
4185
4186 /**********************************************************************
4187  *         SetMenuContextHelpId32    (USER32.488)
4188  */
4189 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpId)
4190 {
4191         FIXME(menu, "SetMenuContextHelpId, stub\n");
4192         return 0;
4193 }
4194
4195 /**********************************************************************
4196  *         GetMenuContextHelpId16    (USER.385)
4197  */
4198 DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4199 {
4200         return GetMenuContextHelpId16( hMenu );
4201 }
4202  
4203 /**********************************************************************
4204  *         GetMenuContextHelpId32    (USER32.488)
4205  */
4206 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4207 {
4208         FIXME(menu, "GetMenuContextHelpId, stub\n");
4209         return 0;
4210 }
4211