4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
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.
23 #include "sysmetrics.h"
30 #include "nonclient.h"
39 UINT32 MENU_BarItemTopNudge
;
40 UINT32 MENU_BarItemLeftNudge
;
41 UINT32 MENU_ItemTopNudge
;
42 UINT32 MENU_ItemLeftNudge
;
43 UINT32 MENU_HighlightTopNudge
;
44 UINT32 MENU_HighlightLeftNudge
;
45 UINT32 MENU_HighlightBottomNudge
;
46 UINT32 MENU_HighlightRightNudge
;
48 /* internal popup menu window messages */
50 #define MM_SETMENUHANDLE (WM_USER + 0)
51 #define MM_GETMENUHANDLE (WM_USER + 1)
53 /* Menu item structure */
55 /* ----------- MENUITEMINFO Stuff ----------- */
56 UINT32 fType
; /* Item type. */
57 UINT32 fState
; /* Item state. */
58 UINT32 wID
; /* Item id. */
59 HMENU32 hSubMenu
; /* Pop-up menu. */
60 HBITMAP32 hCheckBit
; /* Bitmap when checked. */
61 HBITMAP32 hUnCheckBit
; /* Bitmap when unchecked. */
62 LPSTR text
; /* Item text or bitmap handle. */
63 DWORD dwItemData
; /* Application defined. */
64 /* ----------- Wine stuff ----------- */
65 RECT32 rect
; /* Item area (relative to menu window) */
66 UINT32 xTab
; /* X position of text after Tab */
69 /* Popup menu structure */
71 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
72 WORD wMagic
; /* Magic number */
73 HQUEUE16 hTaskQ
; /* Task queue for this menu */
74 WORD Width
; /* Width of the whole menu */
75 WORD Height
; /* Height of the whole menu */
76 WORD nItems
; /* Number of items in the menu */
77 HWND32 hWnd
; /* Window containing the menu */
78 MENUITEM
*items
; /* Array of menu items */
79 UINT32 FocusedItem
; /* Currently focused item */
80 } POPUPMENU
, *LPPOPUPMENU
;
82 /* internal flags for menu tracking */
84 #define TF_ENDMENU 0x0001
85 #define TF_SUSPENDPOPUP 0x0002
86 #define TF_SKIPREMOVE 0x0004
91 HMENU32 hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
92 HMENU32 hTopMenu
; /* initial menu */
93 HWND32 hOwnerWnd
; /* where notifications are sent */
97 #define MENU_MAGIC 0x554d /* 'MU' */
98 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
103 /* Internal MENU_TrackMenu() flags */
104 #define TPM_INTERNAL 0xF0000000
105 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
106 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
108 /* popup menu shade thickness */
109 #define POPUP_XSHADE 4
110 #define POPUP_YSHADE 4
112 /* Space between 2 menu bar items */
113 #define MENU_BAR_ITEMS_SPACE 12
115 /* Minimum width of a tab character */
116 #define MENU_TAB_SPACE 8
118 /* Height of a separator item */
119 #define SEPARATOR_HEIGHT 5
121 /* (other menu->FocusedItem values give the position of the focused item) */
122 #define NO_SELECTED_ITEM 0xffff
124 #define MENU_ITEM_TYPE(flags) \
125 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
127 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
129 #define IS_SYSTEM_MENU(menu) \
130 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
131 #define IS_SYSTEM_POPUP(menu) \
132 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
134 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
135 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
136 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
137 MF_POPUP | MF_SYSMENU | MF_HELP)
138 #define STATE_MASK (~TYPE_MASK)
140 /* Dimension of the menu bitmaps */
141 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
142 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
144 static HBITMAP32 hStdRadioCheck
= 0;
145 static HBITMAP32 hStdCheck
= 0;
146 static HBITMAP32 hStdMnArrow
= 0;
147 static HBRUSH32 hShadeBrush
= 0;
148 static HMENU32 MENU_DefSysPopup
= 0; /* Default system menu popup */
150 /* Use global popup window because there's no way 2 menus can
151 * be tracked at the same time. */
153 static WND
* pTopPopupWnd
= 0;
154 static UINT32 uSubPWndLevel
= 0;
156 /* Flag set by EndMenu() to force an exit from menu tracking */
157 static BOOL32 fEndMenu
= FALSE
;
160 /***********************************************************************
161 * debug_print_menuitem
163 * Print a menuitem in readable form.
166 #define debug_print_menuitem(pre, mp, post) \
167 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
169 #define MENUOUT(text) \
170 dsprintf(menu, "%s%s", (count++ ? "," : ""), (text))
172 #define MENUFLAG(bit,text) \
174 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
177 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
180 dbg_decl_str(menu
, 256);
183 UINT32 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
);
190 dsprintf(menu
, ", Typ=");
191 if (typ
== MFT_STRING
)
193 else if (typ
== MFT_SEPARATOR
)
195 else if (typ
== MFT_OWNERDRAW
)
197 else if (typ
== MFT_BITMAP
)
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");
212 dsprintf(menu
, "+0x%x", flags
);
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");
225 dsprintf(menu
, "+0x%x", flags
);
228 dsprintf(menu
, ", Chk=0x%x", mp
->hCheckBit
);
230 dsprintf(menu
, ", Unc=0x%x", mp
->hUnCheckBit
);
232 if (typ
== MFT_STRING
) {
234 dsprintf(menu
, ", Text=\"%s\"", mp
->text
);
236 dsprintf(menu
, ", Text=Null");
237 } else if (mp
->text
== NULL
)
240 dsprintf(menu
, ", Text=%p", mp
->text
);
241 dsprintf(menu
, " }");
243 dsprintf(menu
, "NULL");
246 TRACE(menu
, "%s %s %s\n", prefix
, dbg_str(menu
), postfix
);
252 /***********************************************************************
255 * Return the default system menu.
257 static HMENU32
MENU_CopySysPopup(void)
259 HMENU32 hMenu
= LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU
));
262 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
263 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
267 ERR(menu
, "Unable to load default system menu\n" );
270 TRACE(menu
, "returning %x.\n", hMenu
);
276 /**********************************************************************
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).
285 HMENU32
MENU_GetSysMenu( HWND32 hWnd
, HMENU32 hPopupMenu
)
289 if ((hMenu
= CreateMenu32()))
291 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
292 menu
->wFlags
= MF_SYSMENU
;
295 if (hPopupMenu
== (HMENU32
)(-1))
296 hPopupMenu
= MENU_CopySysPopup();
297 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
301 InsertMenu32A( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
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
;
308 TRACE(menu
,"GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
311 DestroyMenu32( hMenu
);
313 ERR(menu
, "failed to load system menu!\n");
318 /***********************************************************************
321 * Menus initialisation.
326 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
331 /* Load menu bitmaps */
332 hStdCheck
= LoadBitmap32A(0, MAKEINTRESOURCE32A(OBM_CHECK
));
333 hStdRadioCheck
= LoadBitmap32A(0, MAKEINTRESOURCE32A(OBM_RADIOCHECK
));
334 hStdMnArrow
= LoadBitmap32A(0, MAKEINTRESOURCE32A(OBM_MNARROW
));
339 GetObject32A( hStdCheck
, sizeof(bm
), &bm
);
340 check_bitmap_width
= bm
.bmWidth
;
341 check_bitmap_height
= bm
.bmHeight
;
345 /* Assume that radio checks have the same size as regular check. */
352 GetObject32A( hStdMnArrow
, sizeof(bm
), &bm
);
353 arrow_bitmap_width
= bm
.bmWidth
;
354 arrow_bitmap_height
= bm
.bmHeight
;
358 if ((hBitmap
= CreateBitmap32( 8, 8, 1, 1, shade_bits
)))
360 if((hShadeBrush
= CreatePatternBrush32( hBitmap
)))
362 DeleteObject32( hBitmap
);
363 if ((MENU_DefSysPopup
= MENU_CopySysPopup()))
371 /***********************************************************************
372 * MENU_InitSysMenuPopup
374 * Grey the appropriate items in System menu.
376 static void MENU_InitSysMenuPopup( HMENU32 hmenu
, DWORD style
, DWORD clsStyle
)
380 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
381 EnableMenuItem32( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
382 gray
= ((style
& WS_MAXIMIZE
) != 0);
383 EnableMenuItem32( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
384 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
385 EnableMenuItem32( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
386 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
387 EnableMenuItem32( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
388 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
389 EnableMenuItem32( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
390 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
391 EnableMenuItem32( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
395 /******************************************************************************
397 * UINT32 MENU_GetStartOfNextColumn(
400 *****************************************************************************/
402 static UINT32
MENU_GetStartOfNextColumn(
405 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
406 UINT32 i
= menu
->FocusedItem
+ 1;
409 return NO_SELECTED_ITEM
;
411 if( i
== NO_SELECTED_ITEM
)
414 for( ; i
< menu
->nItems
; ++i
) {
415 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
419 return NO_SELECTED_ITEM
;
423 /******************************************************************************
425 * UINT32 MENU_GetStartOfPrevColumn(
428 *****************************************************************************/
430 static UINT32
MENU_GetStartOfPrevColumn(
433 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
437 return NO_SELECTED_ITEM
;
439 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
440 return NO_SELECTED_ITEM
;
442 /* Find the start of the column */
444 for(i
= menu
->FocusedItem
; i
!= 0 &&
445 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
449 return NO_SELECTED_ITEM
;
451 for(--i
; i
!= 0; --i
) {
452 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
456 TRACE(menu
, "ret %d.\n", i
);
463 /***********************************************************************
466 * Find a menu item. Return a pointer on the item, and modifies *hmenu
467 * in case the item was in a sub-menu.
469 static MENUITEM
*MENU_FindItem( HMENU32
*hmenu
, UINT32
*nPos
, UINT32 wFlags
)
474 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
475 if (wFlags
& MF_BYPOSITION
)
477 if (*nPos
>= menu
->nItems
) return NULL
;
478 return &menu
->items
[*nPos
];
482 MENUITEM
*item
= menu
->items
;
483 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
485 if (item
->wID
== *nPos
)
490 else if (item
->fType
& MF_POPUP
)
492 HMENU32 hsubmenu
= item
->hSubMenu
;
493 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
505 /***********************************************************************
508 static void MENU_FreeItemData( MENUITEM
* item
)
511 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
512 HeapFree( SystemHeap
, 0, item
->text
);
515 /***********************************************************************
516 * MENU_FindItemByCoords
518 * Find the item at the specified coordinates (screen coords). Does
519 * not work for child windows and therefore should not be called for
520 * an arbitrary system menu.
522 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
523 POINT32 pt
, UINT32
*pos
)
529 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
530 pt
.x
-= wndPtr
->rectWindow
.left
;
531 pt
.y
-= wndPtr
->rectWindow
.top
;
533 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
535 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
536 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
546 /***********************************************************************
549 * Find the menu item selected by a key press.
550 * Return item id, -1 if none, -2 if we should close the menu.
552 static UINT32
MENU_FindItemByKey( HWND32 hwndOwner
, HMENU32 hmenu
,
553 UINT32 key
, BOOL32 forceMenuChar
)
555 TRACE(menu
,"\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
557 if (!IsMenu32( hmenu
))
559 WND
* w
= WIN_FindWndPtr(hwndOwner
);
560 hmenu
= GetSubMenu32(w
->hSysMenu
, 0);
565 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
566 MENUITEM
*item
= menu
->items
;
574 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
576 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
578 char *p
= strchr( item
->text
, '&' );
579 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
583 menuchar
= SendMessage32A( hwndOwner
, WM_MENUCHAR
,
584 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
585 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
586 if (HIWORD(menuchar
) == 1) return (UINT32
)(-2);
592 /***********************************************************************
595 * Calculate the size of the menu item and store it in lpitem->rect.
597 static void MENU_CalcItemSize( HDC32 hdc
, MENUITEM
*lpitem
, HWND32 hwndOwner
,
598 INT32 orgX
, INT32 orgY
, BOOL32 menuBar
)
603 TRACE(menu
, "HDC 0x%x at (%d,%d)\n",
605 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
606 (menuBar
? " (MenuBar)" : ""));
608 SetRect32( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
610 if (lpitem
->fType
& MF_OWNERDRAW
)
612 MEASUREITEMSTRUCT32 mis
;
613 mis
.CtlType
= ODT_MENU
;
614 mis
.itemID
= lpitem
->wID
;
615 mis
.itemData
= (DWORD
)lpitem
->text
;
618 SendMessage32A( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
619 lpitem
->rect
.bottom
+= mis
.itemHeight
;
620 lpitem
->rect
.right
+= mis
.itemWidth
;
621 TRACE(menu
, "%08x %dx%d\n",
622 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
626 if (lpitem
->fType
& MF_SEPARATOR
)
628 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
634 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
635 if (lpitem
->fType
& MF_POPUP
)
636 lpitem
->rect
.right
+= arrow_bitmap_width
;
639 if (lpitem
->fType
& MF_BITMAP
)
642 if (GetObject32A( (HBITMAP32
)lpitem
->text
, sizeof(bm
), &bm
))
644 lpitem
->rect
.right
+= bm
.bmWidth
;
645 lpitem
->rect
.bottom
+= bm
.bmHeight
;
650 /* If we get here, then it must be a text item */
652 if (IS_STRING_ITEM( lpitem
->fType
))
654 dwSize
= GetTextExtent( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
655 lpitem
->rect
.right
+= LOWORD(dwSize
);
656 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
659 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
660 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
662 /* Item contains a tab (only meaningful in popup menus) */
663 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
664 LOWORD( GetTextExtent( hdc
, lpitem
->text
,
665 (int)(p
- lpitem
->text
) ));
666 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
670 if (strchr( lpitem
->text
, '\b' ))
671 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
672 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
673 - arrow_bitmap_width
;
679 /***********************************************************************
680 * MENU_PopupMenuCalcSize
682 * Calculate the size of a popup menu.
684 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND32 hwndOwner
)
689 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
691 lppop
->Width
= lppop
->Height
= 0;
692 if (lppop
->nItems
== 0) return;
695 maxX
= SYSMETRICS_CXBORDER
;
696 while (start
< lppop
->nItems
)
698 lpitem
= &lppop
->items
[start
];
700 orgY
= SYSMETRICS_CYBORDER
;
701 maxTab
= maxTabWidth
= 0;
703 /* Parse items until column break or end of menu */
704 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
707 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
712 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
713 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
714 maxX
= MAX( maxX
, lpitem
->rect
.right
);
715 orgY
= lpitem
->rect
.bottom
;
716 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
718 maxTab
= MAX( maxTab
, lpitem
->xTab
);
719 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
723 /* Finish the column (set all items to the largest width found) */
724 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
725 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
727 lpitem
->rect
.right
= maxX
;
728 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
729 lpitem
->xTab
= maxTab
;
731 lppop
->Height
= MAX( lppop
->Height
, orgY
);
735 ReleaseDC32( 0, hdc
);
739 /***********************************************************************
740 * MENU_MenuBarCalcSize
742 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
743 * height is off by 1 pixel which causes lengthy window relocations when
744 * active document window is maximized/restored.
746 * Calculate the size of the menu bar.
748 static void MENU_MenuBarCalcSize( HDC32 hdc
, LPRECT32 lprect
,
749 LPPOPUPMENU lppop
, HWND32 hwndOwner
)
752 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
754 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
755 if (lppop
->nItems
== 0) return;
756 TRACE(menu
,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
757 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
758 lppop
->Width
= lprect
->right
- lprect
->left
;
763 while (start
< lppop
->nItems
)
765 lpitem
= &lppop
->items
[start
];
769 /* Parse items until line break or end of menu */
770 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
772 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
774 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
776 TRACE(menu
, "calling MENU_CalcItemSize org=(%d, %d)\n",
778 debug_print_menuitem (" item: ", lpitem
, "");
779 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
780 if (lpitem
->rect
.right
> lprect
->right
)
782 if (i
!= start
) break;
783 else lpitem
->rect
.right
= lprect
->right
;
785 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
786 orgX
= lpitem
->rect
.right
;
789 /* Finish the line (set all items to the largest height found) */
790 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
793 lprect
->bottom
= maxY
;
794 lppop
->Height
= lprect
->bottom
- lprect
->top
;
796 /* Flush right all items between the MF_HELP and the last item */
797 /* (if several lines, only move the last line) */
800 lpitem
= &lppop
->items
[lppop
->nItems
-1];
801 orgY
= lpitem
->rect
.top
;
802 orgX
= lprect
->right
;
803 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
805 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
806 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
807 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
808 lpitem
->rect
.right
= orgX
;
809 orgX
= lpitem
->rect
.left
;
814 /***********************************************************************
817 * Draw a single menu item.
819 static void MENU_DrawMenuItem( HWND32 hwnd
, HDC32 hdc
, MENUITEM
*lpitem
,
820 UINT32 height
, BOOL32 menuBar
, UINT32 odaction
)
824 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
826 if (lpitem
->fType
& MF_SYSMENU
)
828 if( !IsIconic32(hwnd
) ) {
830 NC_DrawSysButton95( hwnd
, hdc
,
832 (MF_HILITE
| MF_MOUSESELECT
) );
834 NC_DrawSysButton( hwnd
, hdc
,
836 (MF_HILITE
| MF_MOUSESELECT
) );
842 if (lpitem
->fType
& MF_OWNERDRAW
)
844 DRAWITEMSTRUCT32 dis
;
846 dis
.CtlType
= ODT_MENU
;
847 dis
.itemID
= lpitem
->wID
;
848 dis
.itemData
= (DWORD
)lpitem
->text
;
850 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
851 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
852 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
853 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
856 dis
.rcItem
= lpitem
->rect
;
857 TRACE(menu
, "Ownerdraw: itemID=%d, itemState=%d, itemAction=%d, "
858 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}, rcItem=%p\n",dis
.itemID
,
859 dis
.itemState
, dis
.itemAction
, dis
.hwndItem
, dis
.hDC
,
860 dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
861 dis
.rcItem
.bottom
, dis
.rcItem
);
862 SendMessage32A( GetWindow32(hwnd
,GW_OWNER
), WM_DRAWITEM
, 0, (LPARAM
)&dis
);
866 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
869 /* Draw the background */
870 if(TWEAK_Win95Look
) {
880 InflateRect32( &rect, -1, -1 );
884 if (lpitem
->fState
& MF_HILITE
) {
886 r
.top
+= MENU_HighlightTopNudge
;
887 r
.bottom
+= MENU_HighlightBottomNudge
;
888 r
.left
+= MENU_HighlightLeftNudge
;
889 r
.right
+= MENU_HighlightRightNudge
;
890 FillRect32( hdc
, &r
, GetSysColorBrush32(COLOR_HIGHLIGHT
) );
894 r
.top
+= MENU_HighlightTopNudge
;
895 r
.bottom
+= MENU_HighlightBottomNudge
;
896 r
.left
+= MENU_HighlightLeftNudge
;
897 r
.right
+= MENU_HighlightRightNudge
;
898 FillRect32( hdc
, &r
, GetSysColorBrush32(COLOR_MENU
) );
901 SetBkMode32( hdc
, TRANSPARENT
);
903 /* Draw the separator bar (if any) */
905 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
908 TWEAK_DrawMenuSeparatorVert95(hdc
, rect
.left
- 1, 3, height
- 3);
910 SelectObject32( hdc
, GetSysColorPen32(COLOR_WINDOWFRAME
) );
911 MoveTo( hdc
, rect
.left
, 0 );
912 LineTo32( hdc
, rect
.left
, height
);
915 if (lpitem
->fType
& MF_SEPARATOR
)
918 TWEAK_DrawMenuSeparatorHoriz95(hdc
, rect
.left
+ 1,
919 rect
.top
+ SEPARATOR_HEIGHT
/ 2 + 1,
922 SelectObject32( hdc
, GetSysColorPen32(COLOR_WINDOWFRAME
) );
923 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
924 LineTo32( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
932 if (lpitem
->fState
& MF_HILITE
)
934 if (lpitem
->fState
& MF_GRAYED
)
935 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
937 SetTextColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHTTEXT
) );
938 SetBkColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHT
) );
942 if (lpitem
->fState
& MF_GRAYED
)
943 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
945 SetTextColor32( hdc
, GetSysColor32( COLOR_MENUTEXT
) );
946 SetBkColor32( hdc
, GetSysColor32( COLOR_MENU
) );
951 INT32 y
= rect
.top
+ rect
.bottom
;
953 /* Draw the check mark
955 * Custom checkmark bitmaps are monochrome but not always 1bpp.
956 * In this case we want GRAPH_DrawBitmap() to copy a plane which
957 * is 1 for a white pixel and 0 for a black one.
960 if (lpitem
->fState
& MF_CHECKED
)
963 lpitem
->hCheckBit
? lpitem
->hCheckBit
:
964 ((lpitem
->fType
& MFT_RADIOCHECK
)
965 ? hStdRadioCheck
: hStdCheck
);
966 GRAPH_DrawBitmap( hdc
, bm
, rect
.left
,
967 (y
- check_bitmap_height
) / 2,
968 0, 0, check_bitmap_width
,
969 check_bitmap_height
, TRUE
);
970 } else if (lpitem
->hUnCheckBit
)
971 GRAPH_DrawBitmap( hdc
, lpitem
->hUnCheckBit
, rect
.left
,
972 (y
- check_bitmap_height
) / 2, 0, 0,
973 check_bitmap_width
, check_bitmap_height
, TRUE
);
975 /* Draw the popup-menu arrow */
977 if (lpitem
->fType
& MF_POPUP
)
979 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
980 rect
.right
-arrow_bitmap_width
-1,
981 (y
- arrow_bitmap_height
) / 2, 0, 0,
982 arrow_bitmap_width
, arrow_bitmap_height
, FALSE
);
985 rect
.left
+= check_bitmap_width
;
986 rect
.right
-= arrow_bitmap_width
;
989 /* Draw the item text or bitmap */
991 if (lpitem
->fType
& MF_BITMAP
)
993 GRAPH_DrawBitmap( hdc
, (HBITMAP32
)lpitem
->text
,
994 rect
.left
, rect
.top
, 0, 0,
995 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, FALSE
);
998 /* No bitmap - process text if present */
999 else if (IS_STRING_ITEM(lpitem
->fType
))
1005 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1006 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1007 i
= strlen( lpitem
->text
);
1009 rect
.top
+= MENU_BarItemTopNudge
;
1010 rect
.left
+= MENU_BarItemLeftNudge
;
1014 for (i
= 0; lpitem
->text
[i
]; i
++)
1015 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1018 rect
.top
+= MENU_ItemTopNudge
;
1019 rect
.left
+= MENU_ItemLeftNudge
;
1022 if(!TWEAK_Win95Look
|| !(lpitem
->fState
& MF_GRAYED
)) {
1023 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
1024 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1027 if (!(lpitem
->fState
& MF_HILITE
))
1033 SetTextColor32(hdc
, RGB(0xff, 0xff, 0xff));
1034 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
1035 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1041 SetTextColor32(hdc
, RGB(0x80, 0x80, 0x80));
1042 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
1043 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1046 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1048 if (lpitem
->text
[i
] == '\t')
1050 rect
.left
= lpitem
->xTab
;
1051 DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
1052 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1054 else DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
1055 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
1061 /***********************************************************************
1062 * MENU_DrawPopupMenu
1064 * Paint a popup menu.
1066 static void MENU_DrawPopupMenu( HWND32 hwnd
, HDC32 hdc
, HMENU32 hmenu
)
1068 HBRUSH32 hPrevBrush
= 0;
1071 GetClientRect32( hwnd
, &rect
);
1073 /* if(!TWEAK_Win95Look) { */
1074 rect
.bottom
-= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1075 rect
.right
-= POPUP_XSHADE
* SYSMETRICS_CXBORDER
;
1078 if((hPrevBrush
= SelectObject32( hdc
, GetSysColorBrush32(COLOR_MENU
) )))
1082 Rectangle32( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1084 hPrevPen
= SelectObject32( hdc
, GetStockObject32( NULL_PEN
) );
1090 /* draw 3-d shade */
1091 if(!TWEAK_Win95Look
) {
1092 SelectObject32( hdc
, hShadeBrush
);
1093 SetBkMode32( hdc
, TRANSPARENT
);
1094 ropPrev
= SetROP232( hdc
, R2_MASKPEN
);
1096 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1097 PatBlt32( hdc
, i
& 0xfffffffe,
1098 rect
.top
+ POPUP_YSHADE
*SYSMETRICS_CYBORDER
,
1099 i
%2 + POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1100 rect
.bottom
- rect
.top
, 0x00a000c9 );
1102 PatBlt32( hdc
, rect
.left
+ POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1103 i
& 0xfffffffe,rect
.right
- rect
.left
,
1104 i
%2 + POPUP_YSHADE
*SYSMETRICS_CYBORDER
, 0x00a000c9 );
1105 SelectObject32( hdc
, hPrevPen
);
1106 SelectObject32( hdc
, hPrevBrush
);
1107 SetROP232( hdc
, ropPrev
);
1110 TWEAK_DrawReliefRect95(hdc
, &rect
);
1112 /* draw menu items */
1114 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1115 if (menu
&& menu
->nItems
)
1120 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1121 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
,
1125 } else SelectObject32( hdc
, hPrevBrush
);
1130 /***********************************************************************
1133 * Paint a menu bar. Returns the height of the menu bar.
1135 UINT32
MENU_DrawMenuBar( HDC32 hDC
, LPRECT32 lprect
, HWND32 hwnd
,
1136 BOOL32 suppress_draw
)
1140 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1142 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU16
)wndPtr
->wIDmenu
);
1143 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
1144 TRACE(menu
,"(%04x, %p, %p); !\n",
1145 hDC
, lprect
, lppop
);
1146 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1147 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1148 if (suppress_draw
) return lppop
->Height
;
1153 FillRect32(hDC
, lprect
, GetSysColorBrush32(COLOR_MENU
) );
1155 if(!TWEAK_Win95Look
) {
1156 SelectObject32( hDC
, GetSysColorPen32(COLOR_WINDOWFRAME
) );
1157 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
1158 LineTo32( hDC
, lprect
->right
, lprect
->bottom
);
1161 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
1162 for (i
= 0; i
< lppop
->nItems
; i
++)
1164 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
,
1167 return lppop
->Height
;
1171 /***********************************************************************
1172 * MENU_PatchResidentPopup
1174 BOOL32
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1180 TRACE(menu
,"patching resident popup: %04x %04x [%04x %04x]\n",
1181 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTopPopupWnd
->hmemTaskQ
,
1182 pTopPopupWnd
->owner
? pTopPopupWnd
->owner
->hwndSelf
: 0);
1184 switch( checkQueue
)
1186 case 0: /* checkWnd is the new popup owner */
1189 pTopPopupWnd
->owner
= checkWnd
;
1190 if( pTopPopupWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1191 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1195 case 0xFFFF: /* checkWnd is destroyed */
1196 if( pTopPopupWnd
->owner
== checkWnd
)
1197 pTopPopupWnd
->owner
= NULL
;
1200 default: /* checkQueue is exiting */
1201 if( pTopPopupWnd
->hmemTaskQ
== checkQueue
)
1203 hTask
= QUEUE_GetQueueTask( pTopPopupWnd
->hmemTaskQ
);
1204 hTask
= TASK_GetNextTask( hTask
);
1211 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1214 pTopPopupWnd
->hInstance
= task
->hInstance
;
1215 pTopPopupWnd
->hmemTaskQ
= task
->hQueue
;
1218 else WARN(menu
,"failed to patch resident popup.\n");
1224 /***********************************************************************
1227 * Display a popup menu.
1229 static BOOL32
MENU_ShowPopup( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 id
,
1230 INT32 x
, INT32 y
, INT32 xanchor
, INT32 yanchor
)
1233 WND
*wndOwner
= NULL
;
1235 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1236 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1238 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1239 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1242 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1244 UINT32 width
, height
;
1246 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1248 /* adjust popup menu pos so that it fits within the desktop */
1250 width
= menu
->Width
+ SYSMETRICS_CXBORDER
;
1251 height
= menu
->Height
+ SYSMETRICS_CYBORDER
;
1253 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1256 x
-= width
- xanchor
;
1257 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1258 x
= SYSMETRICS_CXSCREEN
- width
;
1262 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1265 y
-= height
+ yanchor
;
1266 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1267 y
= SYSMETRICS_CYSCREEN
- height
;
1271 width
+= POPUP_XSHADE
* SYSMETRICS_CXBORDER
; /* add space for shading */
1272 height
+= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1274 /* NOTE: In Windows, top menu popup is not owned. */
1275 if (!pTopPopupWnd
) /* create top level popup menu window */
1277 assert( uSubPWndLevel
== 0 );
1279 pTopPopupWnd
= WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
1280 WS_POPUP
, x
, y
, width
, height
,
1281 hwndOwner
, 0, wndOwner
->hInstance
,
1283 if (!pTopPopupWnd
) return FALSE
;
1284 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1289 /* create a new window for the submenu */
1291 menu
->hWnd
= CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
1292 WS_POPUP
, x
, y
, width
, height
,
1293 menu
->hWnd
, 0, wndOwner
->hInstance
,
1295 if( !menu
->hWnd
) return FALSE
;
1297 else /* top level popup menu window already exists */
1299 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1301 MENU_PatchResidentPopup( 0, wndOwner
);
1302 SendMessage16( pTopPopupWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1304 /* adjust its size */
1306 SetWindowPos32( menu
->hWnd
, 0, x
, y
, width
, height
,
1307 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1310 uSubPWndLevel
++; /* menu level counter */
1312 /* Display the window */
1314 SetWindowPos32( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1315 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1316 UpdateWindow32( menu
->hWnd
);
1323 /***********************************************************************
1326 static void MENU_SelectItem( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 wIndex
,
1327 BOOL32 sendMenuSelect
)
1332 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1333 if (!lppop
->nItems
) return;
1335 if ((wIndex
!= NO_SELECTED_ITEM
) &&
1336 (lppop
->items
[wIndex
].fType
& MF_SEPARATOR
))
1337 wIndex
= NO_SELECTED_ITEM
;
1339 if (lppop
->FocusedItem
== wIndex
) return;
1340 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC32( lppop
->hWnd
);
1341 else hdc
= GetDCEx32( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1343 /* Clear previous highlighted item */
1344 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1346 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1347 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
1348 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1352 /* Highlight new item (if any) */
1353 lppop
->FocusedItem
= wIndex
;
1354 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1356 lppop
->items
[lppop
->FocusedItem
].fState
|= MF_HILITE
;
1357 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
1358 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1362 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1363 SendMessage16( hwndOwner
, WM_MENUSELECT
, ip
->wID
,
1364 MAKELONG(ip
->fType
| (ip
->fState
| MF_MOUSESELECT
),
1368 else if (sendMenuSelect
)
1369 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
1370 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
1372 ReleaseDC32( lppop
->hWnd
, hdc
);
1376 /***********************************************************************
1377 * MENU_MoveSelection
1379 * Moves currently selected item according to the offset parameter.
1380 * If there is no selection then it should select the last item if
1381 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1383 static void MENU_MoveSelection( HWND32 hwndOwner
, HMENU32 hmenu
, INT32 offset
)
1388 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1389 if (!menu
->items
) return;
1391 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1393 if( menu
->nItems
== 1 ) return; else
1394 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1396 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1398 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1403 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1404 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1405 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1407 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1413 /**********************************************************************
1416 * Set an item flags, id and text ptr. Called by InsertMenu() and
1419 static BOOL32
MENU_SetItemData( MENUITEM
*item
, UINT32 flags
, UINT32 id
,
1422 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1424 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1426 if (IS_STRING_ITEM(flags
))
1430 flags
|= MF_SEPARATOR
;
1436 /* Item beginning with a backspace is a help item */
1442 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1446 else if (flags
& MF_BITMAP
) item
->text
= (LPSTR
)(HBITMAP32
)LOWORD(str
);
1447 else if (flags
& MF_OWNERDRAW
) item
->text
= (LPSTR
)str
;
1448 else item
->text
= NULL
;
1450 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1451 DestroyMenu32( item
->hSubMenu
); /* ModifyMenu() spec */
1453 if (flags
& MF_POPUP
)
1455 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)id
);
1456 if (IS_A_MENU(menu
)) menu
->wFlags
|= MF_POPUP
;
1468 if (flags
& MF_POPUP
)
1469 item
->hSubMenu
= id
;
1471 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1472 flags
|= MF_POPUP
; /* keep popup */
1474 item
->fType
= flags
& TYPE_MASK
;
1475 item
->fState
= (flags
& STATE_MASK
) &
1476 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1478 SetRectEmpty32( &item
->rect
);
1479 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1481 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1486 /**********************************************************************
1489 * Insert a new item into a menu.
1491 static MENUITEM
*MENU_InsertItem( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
)
1496 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1498 WARN(menu
, "%04x not a menu handle\n",
1503 /* Find where to insert new item */
1505 if ((flags
& MF_BYPOSITION
) &&
1506 ((pos
== (UINT32
)-1) || (pos
== menu
->nItems
)))
1508 /* Special case: append to menu */
1509 /* Some programs specify the menu length to do that */
1514 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1516 WARN(menu
, "item %x not found\n",
1520 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1522 WARN(menu
,"%04x not a menu handle\n",
1528 /* Create new items array */
1530 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1533 WARN(menu
, "allocation failed\n" );
1536 if (menu
->nItems
> 0)
1538 /* Copy the old array into the new */
1539 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1540 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1541 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1542 HeapFree( SystemHeap
, 0, menu
->items
);
1544 menu
->items
= newItems
;
1546 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1547 return &newItems
[pos
];
1551 /**********************************************************************
1552 * MENU_ParseResource
1554 * Parse a standard menu resource and add items to the menu.
1555 * Return a pointer to the end of the resource.
1557 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU32 hMenu
, BOOL32 unicode
)
1564 flags
= GET_WORD(res
);
1565 res
+= sizeof(WORD
);
1566 if (!(flags
& MF_POPUP
))
1569 res
+= sizeof(WORD
);
1571 if (!IS_STRING_ITEM(flags
))
1572 ERR(menu
, "not a string item %04x\n", flags
);
1574 if (!unicode
) res
+= strlen(str
) + 1;
1575 else res
+= (lstrlen32W((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1576 if (flags
& MF_POPUP
)
1578 HMENU32 hSubMenu
= CreatePopupMenu32();
1579 if (!hSubMenu
) return NULL
;
1580 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1582 if (!unicode
) AppendMenu32A( hMenu
, flags
, (UINT32
)hSubMenu
, str
);
1583 else AppendMenu32W( hMenu
, flags
, (UINT32
)hSubMenu
, (LPCWSTR
)str
);
1585 else /* Not a popup */
1587 if (!unicode
) AppendMenu32A( hMenu
, flags
, id
, *str
? str
: NULL
);
1588 else AppendMenu32W( hMenu
, flags
, id
,
1589 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1591 } while (!(flags
& MF_END
));
1596 /**********************************************************************
1597 * MENUEX_ParseResource
1599 * Parse an extended menu resource and add items to the menu.
1600 * Return a pointer to the end of the resource.
1602 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU32 hMenu
)
1606 MENUITEMINFO32W mii
;
1608 mii
.cbSize
= sizeof(mii
);
1609 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1610 mii
.fType
= GET_DWORD(res
);
1611 res
+= sizeof(DWORD
);
1612 mii
.fState
= GET_DWORD(res
);
1613 res
+= sizeof(DWORD
);
1614 mii
.wID
= GET_DWORD(res
);
1615 res
+= sizeof(DWORD
);
1616 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1617 res
+= sizeof(WORD
);
1618 /* Align the text on a word boundary. */
1619 res
+= (~((int)res
- 1)) & 1;
1620 mii
.dwTypeData
= (LPWSTR
) res
;
1621 res
+= (1 + lstrlen32W(mii
.dwTypeData
)) * sizeof(WCHAR
);
1622 /* Align the following fields on a dword boundary. */
1623 res
+= (~((int)res
- 1)) & 3;
1625 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
1627 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
1629 TRACE(menu
, "Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1630 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
1631 HeapFree( GetProcessHeap(), 0, newstr
);
1634 if (resinfo
& 1) { /* Pop-up? */
1635 DWORD helpid
= GET_DWORD(res
); /* FIXME: use this. */
1636 res
+= sizeof(DWORD
);
1637 mii
.hSubMenu
= CreatePopupMenu32();
1640 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1641 DestroyMenu32(mii
.hSubMenu
);
1644 mii
.fMask
|= MIIM_SUBMENU
;
1645 mii
.fType
|= MF_POPUP
;
1647 InsertMenuItem32W(hMenu
, -1, MF_BYPOSITION
, &mii
);
1648 } while (!(resinfo
& MF_END
));
1653 /***********************************************************************
1656 * Return the handle of the selected sub-popup menu (if any).
1658 static HMENU32
MENU_GetSubPopup( HMENU32 hmenu
)
1663 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1665 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1667 item
= &menu
->items
[menu
->FocusedItem
];
1668 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1669 return item
->hSubMenu
;
1674 /***********************************************************************
1675 * MENU_HideSubPopups
1677 * Hide the sub-popup menus of this menu.
1679 static void MENU_HideSubPopups( HWND32 hwndOwner
, HMENU32 hmenu
,
1680 BOOL32 sendMenuSelect
)
1682 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);;
1684 if (menu
&& uSubPWndLevel
)
1690 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1692 item
= &menu
->items
[menu
->FocusedItem
];
1693 if (!(item
->fType
& MF_POPUP
) ||
1694 !(item
->fState
& MF_MOUSESELECT
)) return;
1695 item
->fState
&= ~MF_MOUSESELECT
;
1696 hsubmenu
= item
->hSubMenu
;
1699 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1700 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1701 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1703 if (submenu
->hWnd
== pTopPopupWnd
->hwndSelf
)
1705 ShowWindow32( submenu
->hWnd
, SW_HIDE
);
1710 DestroyWindow32( submenu
->hWnd
);
1717 /***********************************************************************
1720 * Display the sub-menu of the selected item of this menu.
1721 * Return the handle of the submenu, or hmenu if no submenu to display.
1723 static HMENU32
MENU_ShowSubPopup( HWND32 hwndOwner
, HMENU32 hmenu
,
1724 BOOL32 selectFirst
)
1732 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1734 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
1735 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return hmenu
;
1737 item
= &menu
->items
[menu
->FocusedItem
];
1738 if (!(item
->fType
& MF_POPUP
) ||
1739 (item
->fState
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1741 /* message must be send before using item,
1742 because nearly everything may by changed by the application ! */
1744 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM16
)item
->hSubMenu
,
1745 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
1747 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
1748 if (!(item
->fState
& MF_HILITE
))
1750 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC32( menu
->hWnd
);
1751 else hdc
= GetDCEx32( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1752 item
->fState
|= MF_HILITE
;
1753 MENU_DrawMenuItem( menu
->hWnd
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
1754 ReleaseDC32( menu
->hWnd
, hdc
);
1756 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
1759 item
->fState
|= MF_MOUSESELECT
;
1761 if (IS_SYSTEM_MENU(menu
))
1763 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, wndPtr
->class->style
);
1765 NC_GetSysPopupPos( wndPtr
, &rect
);
1766 rect
.top
= rect
.bottom
;
1767 rect
.right
= SYSMETRICS_CXSIZE
;
1768 rect
.bottom
= SYSMETRICS_CYSIZE
;
1772 if (menu
->wFlags
& MF_POPUP
)
1774 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
;
1775 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
1776 rect
.right
= item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
;
1777 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
1781 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
1782 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
1783 rect
.right
= item
->rect
.right
- item
->rect
.left
;
1784 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
1788 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
1789 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1791 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
1792 return item
->hSubMenu
;
1795 /***********************************************************************
1798 * Walks menu chain trying to find a menu pt maps to.
1800 static HMENU32
MENU_PtMenu( HMENU32 hMenu
, POINT16 pt
)
1802 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
1803 register UINT32 ht
= menu
->FocusedItem
;
1805 /* try subpopup first (if any) */
1806 ht
= (ht
!= NO_SELECTED_ITEM
&&
1807 (menu
->items
[ht
].fType
& MF_POPUP
) &&
1808 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
1809 ? (UINT32
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
1811 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
1813 ht
= (UINT32
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
1814 if( menu
->wFlags
& MF_POPUP
)
1815 ht
= (ht
!= (UINT32
)HTNOWHERE
&&
1816 ht
!= (UINT32
)HTERROR
) ? (UINT32
)hMenu
: 0;
1819 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
1821 ht
= ( ht
== HTSYSMENU
) ? (UINT32
)(wndPtr
->hSysMenu
)
1822 : ( ht
== HTMENU
) ? (UINT32
)(wndPtr
->wIDmenu
) : 0;
1828 /***********************************************************************
1829 * MENU_ExecFocusedItem
1831 * Execute a menu item (for instance when user pressed Enter).
1832 * Return TRUE if we can go on with menu tracking.
1834 static BOOL32
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU32 hMenu
)
1837 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
1838 if (!menu
|| !menu
->nItems
||
1839 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return TRUE
;
1841 item
= &menu
->items
[menu
->FocusedItem
];
1843 TRACE(menu
, "%08x %08x %08x\n",
1844 hMenu
, item
->wID
, item
->hSubMenu
);
1846 if (!(item
->fType
& MF_POPUP
))
1848 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
1850 if( menu
->wFlags
& MF_SYSMENU
)
1852 PostMessage16( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
1853 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
1856 PostMessage16( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
1863 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hMenu
, TRUE
);
1869 /***********************************************************************
1870 * MENU_SwitchTracking
1872 * Helper function for menu navigation routines.
1874 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU32 hPtMenu
, UINT32 id
)
1876 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1877 POPUPMENU
*topmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
1879 if( pmt
->hTopMenu
!= hPtMenu
&&
1880 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
1882 /* both are top level menus (system and menu-bar) */
1884 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
1885 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
1886 pmt
->hTopMenu
= hPtMenu
;
1888 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1889 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
);
1893 /***********************************************************************
1896 * Return TRUE if we can go on with menu tracking.
1898 static BOOL32
MENU_ButtonDown( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1903 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1906 if( IS_SYSTEM_MENU(ptmenu
) )
1907 item
= ptmenu
->items
;
1909 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1913 if( ptmenu
->FocusedItem
== id
)
1915 /* nothing to do with already selected non-popup */
1916 if( !(item
->fType
& MF_POPUP
) ) return TRUE
;
1918 if( item
->fState
& MF_MOUSESELECT
)
1920 if( ptmenu
->wFlags
& MF_POPUP
)
1922 /* hide selected subpopup */
1924 MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, TRUE
);
1925 pmt
->hCurrentMenu
= hPtMenu
;
1928 return FALSE
; /* shouldn't get here */
1931 else MENU_SwitchTracking( pmt
, hPtMenu
, id
);
1933 /* try to display a subpopup */
1935 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1938 else WARN(menu
, "\tunable to find clicked item!\n");
1943 /***********************************************************************
1946 * Return TRUE if we can go on with menu tracking.
1948 static BOOL32
MENU_ButtonUp( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1953 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1956 if( IS_SYSTEM_MENU(ptmenu
) )
1957 item
= ptmenu
->items
;
1959 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1961 if( item
&& (ptmenu
->FocusedItem
== id
))
1963 if( !(item
->fType
& MF_POPUP
) )
1964 return MENU_ExecFocusedItem( pmt
, hPtMenu
);
1965 hPtMenu
= item
->hSubMenu
;
1966 if( hPtMenu
== pmt
->hCurrentMenu
)
1968 /* Select first item of sub-popup */
1970 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, NO_SELECTED_ITEM
, FALSE
);
1971 MENU_MoveSelection( pmt
->hOwnerWnd
, hPtMenu
, ITEM_NEXT
);
1980 /***********************************************************************
1983 * Return TRUE if we can go on with menu tracking.
1985 static BOOL32
MENU_MouseMove( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1987 UINT32 id
= NO_SELECTED_ITEM
;
1988 POPUPMENU
*ptmenu
= NULL
;
1992 ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1993 if( IS_SYSTEM_MENU(ptmenu
) )
1996 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1999 if( id
== NO_SELECTED_ITEM
)
2001 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2002 NO_SELECTED_ITEM
, TRUE
);
2004 else if( ptmenu
->FocusedItem
!= id
)
2006 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2007 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2013 /***********************************************************************
2016 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2018 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT32 vk
)
2020 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2022 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2023 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2029 LRESULT l
= SendMessage16( pmt
->hOwnerWnd
, WM_NEXTMENU
, (WPARAM16
)vk
,
2030 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2032 TRACE(menu
,"%04x [%04x] -> %04x [%04x]\n",
2033 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2037 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2039 hNewWnd
= pmt
->hOwnerWnd
;
2040 if( IS_SYSTEM_MENU(menu
) )
2042 /* switch to the menu bar */
2044 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2047 hNewMenu
= wndPtr
->wIDmenu
;
2050 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hNewMenu
);
2051 id
= menu
->nItems
- 1;
2054 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2056 /* switch to the system menu */
2057 hNewMenu
= wndPtr
->hSysMenu
;
2061 else /* application returned a new menu to switch to */
2063 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2065 if( IsMenu32(hNewMenu
) && IsWindow32(hNewWnd
) )
2067 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2069 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2070 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2072 /* get the real system menu */
2073 hNewMenu
= wndPtr
->hSysMenu
;
2075 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2077 /* FIXME: Not sure what to do here, perhaps,
2078 * try to track hNewMenu as a popup? */
2080 TRACE(menu
," -- got confused.\n");
2087 if( hNewMenu
!= pmt
->hTopMenu
)
2089 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2090 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2091 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2094 if( hNewWnd
!= pmt
->hOwnerWnd
)
2097 pmt
->hOwnerWnd
= hNewWnd
;
2098 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2101 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2102 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
);
2109 /***********************************************************************
2112 * The idea is not to show the popup if the next input message is
2113 * going to hide it anyway.
2115 static BOOL32
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2119 msg
.hwnd
= pmt
->hOwnerWnd
;
2121 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2122 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2127 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2128 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2130 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2131 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2132 if( msg
.message
== WM_KEYDOWN
&&
2133 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2135 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2142 /* failures go through this */
2143 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2147 /***********************************************************************
2150 * Handle a VK_LEFT key event in a menu.
2152 static void MENU_KeyLeft( MTRACKER
* pmt
)
2155 HMENU32 hmenutmp
, hmenuprev
;
2158 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2159 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenutmp
);
2161 /* Try to move 1 column left (if possible) */
2162 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2163 NO_SELECTED_ITEM
) {
2165 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2170 /* close topmost popup */
2171 while (hmenutmp
!= pmt
->hCurrentMenu
)
2173 hmenuprev
= hmenutmp
;
2174 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2177 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2178 pmt
->hCurrentMenu
= hmenuprev
;
2180 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2182 /* move menu bar selection if no more popups are left */
2184 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2185 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2187 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2189 /* A sublevel menu was displayed - display the next one
2190 * unless there is another displacement coming up */
2192 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2193 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2194 pmt
->hTopMenu
, TRUE
);
2200 /***********************************************************************
2203 * Handle a VK_RIGHT key event in a menu.
2205 static void MENU_KeyRight( MTRACKER
* pmt
)
2208 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2211 TRACE(menu
, "MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2213 ((POPUPMENU
*)USER_HEAP_LIN_ADDR(pmt
->hCurrentMenu
))->
2215 pmt
->hTopMenu
, menu
->items
[0].text
);
2217 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2219 /* If already displaying a popup, try to display sub-popup */
2221 hmenutmp
= pmt
->hCurrentMenu
;
2222 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hmenutmp
, TRUE
);
2224 /* if subpopup was displayed then we are done */
2225 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2228 /* Check to see if there's another column */
2229 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2230 NO_SELECTED_ITEM
) {
2231 TRACE(menu
, "Going to %d.\n", nextcol
);
2232 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2237 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2239 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2241 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2242 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2243 } else hmenutmp
= 0;
2245 /* try to move to the next item */
2246 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2247 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2249 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2250 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2251 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2252 pmt
->hTopMenu
, TRUE
);
2257 /***********************************************************************
2260 * Menu tracking code.
2262 static BOOL32
MENU_TrackMenu( HMENU32 hmenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2263 HWND32 hwnd
, const RECT32
*lprect
)
2268 MTRACKER mt
= { 0, hmenu
, hmenu
, hwnd
, {x
, y
} }; /* control struct */
2271 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2273 if (wFlags
& TPM_BUTTONDOWN
) MENU_ButtonDown( &mt
, hmenu
);
2275 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2279 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2280 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2282 /* we have to keep the message in the queue until it's
2283 * clear that menu loop is not over yet. */
2285 if (!MSG_InternalGetMessage( &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2286 MSGF_MENU
, PM_NOREMOVE
, TRUE
)) break;
2288 TranslateMessage16( &msg
);
2289 CONV_POINT16TO32( &msg
.pt
, &mt
.pt
);
2292 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2294 /* Find a menu for this mouse event */
2296 hmenu
= MENU_PtMenu( mt
.hTopMenu
, msg
.pt
);
2300 /* no WM_NC... messages in captured state */
2302 case WM_RBUTTONDBLCLK
:
2303 case WM_RBUTTONDOWN
:
2304 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2306 case WM_LBUTTONDBLCLK
:
2307 case WM_LBUTTONDOWN
:
2308 fEndMenu
|= !MENU_ButtonDown( &mt
, hmenu
);
2312 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2315 /* If outside all menus but inside lprect, ignore it */
2316 if (hmenu
|| !lprect
|| !PtInRect32(lprect
, mt
.pt
))
2318 fEndMenu
|= !MENU_ButtonUp( &mt
, hmenu
);
2324 if ((msg
.wParam
& MK_LBUTTON
) || ((wFlags
& TPM_RIGHTBUTTON
)
2325 && (msg
.wParam
& MK_RBUTTON
)))
2327 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
);
2329 } /* switch(msg.message) - mouse */
2331 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2333 fRemove
= TRUE
; /* Keyboard messages are always removed */
2341 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2342 NO_SELECTED_ITEM
, FALSE
);
2345 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2346 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2349 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2351 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2352 if (!(menu
->wFlags
& MF_POPUP
))
2353 mt
.hCurrentMenu
= MENU_ShowSubPopup( mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
);
2354 else /* otherwise try to move selection */
2355 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2359 MENU_KeyLeft( &mt
);
2363 MENU_KeyRight( &mt
);
2368 fEndMenu
|= !MENU_ExecFocusedItem( &mt
, mt
.hCurrentMenu
);
2378 break; /* WM_KEYDOWN */
2388 break; /* WM_SYSKEYDOWN */
2394 /* Hack to avoid control chars. */
2395 /* We will find a better way real soon... */
2396 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2398 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2399 msg
.wParam
, FALSE
);
2400 if (pos
== (UINT32
)-2) fEndMenu
= TRUE
;
2401 else if (pos
== (UINT32
)-1) MessageBeep32(0);
2404 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
, TRUE
);
2405 fEndMenu
|= !MENU_ExecFocusedItem( &mt
, mt
.hCurrentMenu
);
2409 } /* switch(msg.message) - kbd */
2413 DispatchMessage16( &msg
);
2416 if (!fEndMenu
) fRemove
= TRUE
;
2418 /* finally remove message from the queue */
2420 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2421 PeekMessage16( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2422 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2426 if( IsWindow32( mt
.hOwnerWnd
) )
2428 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2430 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hTopMenu
);
2431 if (menu
&& menu
->wFlags
& MF_POPUP
)
2433 ShowWindow32( menu
->hWnd
, SW_HIDE
);
2436 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2437 SendMessage16( mt
.hOwnerWnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
2443 /***********************************************************************
2446 static BOOL32
MENU_InitTracking(HWND32 hWnd
, HMENU32 hMenu
)
2449 SendMessage16( hWnd
, WM_ENTERMENULOOP
, 0, 0 );
2450 SendMessage16( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2451 SendMessage16( hWnd
, WM_INITMENU
, hMenu
, 0 );
2455 /***********************************************************************
2456 * MENU_TrackMouseMenuBar
2458 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2460 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT32 ht
, POINT32 pt
)
2462 HWND32 hWnd
= wndPtr
->hwndSelf
;
2463 HMENU32 hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2465 if (IsMenu32(hMenu
))
2467 MENU_InitTracking( hWnd
, hMenu
);
2468 MENU_TrackMenu( hMenu
, TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
|
2469 TPM_LEFTALIGN
| TPM_LEFTBUTTON
, pt
.x
, pt
.y
, hWnd
, NULL
);
2471 SendMessage16( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2477 /***********************************************************************
2478 * MENU_TrackKbdMenuBar
2480 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2482 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT32 wParam
, INT32 vkey
)
2484 UINT32 uItem
= NO_SELECTED_ITEM
;
2487 /* find window that has a menu */
2489 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
2490 if( !(wndPtr
= wndPtr
->parent
) ) return;
2492 /* check if we have to track a system menu */
2494 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
2495 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
2497 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
2498 hTrackMenu
= wndPtr
->hSysMenu
;
2500 wParam
|= HTSYSMENU
; /* prevent item lookup */
2503 hTrackMenu
= wndPtr
->wIDmenu
;
2505 if (IsMenu32( hTrackMenu
))
2507 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
);
2509 if( vkey
&& vkey
!= VK_SPACE
)
2511 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
2512 vkey
, (wParam
& HTSYSMENU
) );
2513 if( uItem
>= (UINT32
)(-2) )
2515 if( uItem
== (UINT32
)(-1) ) MessageBeep32(0);
2522 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
2524 if( uItem
== NO_SELECTED_ITEM
)
2525 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
2527 PostMessage16( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
2529 MENU_TrackMenu( hTrackMenu
, TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2530 0, 0, wndPtr
->hwndSelf
, NULL
);
2532 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
2538 /**********************************************************************
2539 * TrackPopupMenu16 (USER.416)
2541 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
2542 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
2546 CONV_RECT16TO32( lpRect
, &r
);
2547 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
2548 lpRect
? &r
: NULL
);
2552 /**********************************************************************
2553 * TrackPopupMenu32 (USER32.549)
2555 BOOL32 WINAPI
TrackPopupMenu32( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2556 INT32 nReserved
, HWND32 hWnd
, const RECT32
*lpRect
)
2561 SendMessage16( hWnd
, WM_INITMENUPOPUP
, (WPARAM16
)hMenu
, 0);
2562 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
2563 ret
= MENU_TrackMenu( hMenu
, wFlags
& ~TPM_INTERNAL
, 0, 0, hWnd
, lpRect
);
2568 /**********************************************************************
2569 * TrackPopupMenuEx (USER32.550)
2571 BOOL32 WINAPI
TrackPopupMenuEx( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2572 HWND32 hWnd
, LPTPMPARAMS lpTpm
)
2574 FIXME(menu
, "not fully implemented\n" );
2575 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, 0, hWnd
,
2576 lpTpm
? &lpTpm
->rcExclude
: NULL
);
2579 /***********************************************************************
2582 * NOTE: Windows has totally different (and undocumented) popup wndproc.
2584 LRESULT WINAPI
PopupMenuWndProc( HWND32 hwnd
, UINT32 message
, WPARAM32 wParam
,
2587 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
2593 CREATESTRUCT32A
*cs
= (CREATESTRUCT32A
*)lParam
;
2594 SetWindowLong32A( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2598 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2599 return MA_NOACTIVATE
;
2604 BeginPaint32( hwnd
, &ps
);
2605 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2606 (HMENU32
)GetWindowLong32A( hwnd
, 0 ) );
2607 EndPaint32( hwnd
, &ps
);
2615 /* zero out global pointer in case resident popup window
2616 * was somehow destroyed. */
2620 if( hwnd
== pTopPopupWnd
->hwndSelf
)
2622 ERR(menu
, "resident popup destroyed!\n");
2624 pTopPopupWnd
= NULL
;
2636 if( !(*(HMENU32
*)wndPtr
->wExtra
) )
2637 ERR(menu
,"no menu to display\n");
2640 *(HMENU32
*)wndPtr
->wExtra
= 0;
2643 case MM_SETMENUHANDLE
:
2645 *(HMENU32
*)wndPtr
->wExtra
= (HMENU32
)wParam
;
2648 case MM_GETMENUHANDLE
:
2650 return *(HMENU32
*)wndPtr
->wExtra
;
2653 return DefWindowProc32A( hwnd
, message
, wParam
, lParam
);
2659 /***********************************************************************
2660 * MENU_GetMenuBarHeight
2662 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2664 UINT32
MENU_GetMenuBarHeight( HWND32 hwnd
, UINT32 menubarWidth
,
2665 INT32 orgX
, INT32 orgY
)
2672 TRACE(menu
, "HWND 0x%x, width %d, "
2673 "at (%d, %d).\n", hwnd
, menubarWidth
, orgX
, orgY
);
2675 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
2676 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
2678 hdc
= GetDCEx32( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2679 SetRect32(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
2680 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
2681 ReleaseDC32( hwnd
, hdc
);
2682 return lppop
->Height
;
2686 /*******************************************************************
2687 * ChangeMenu16 (USER.153)
2689 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
2690 UINT16 id
, UINT16 flags
)
2692 TRACE(menu
,"menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2693 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2694 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
2697 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2698 /* for MF_DELETE. We should check the parameters for all others */
2699 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2701 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
2702 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
2704 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
2705 flags
& MF_BYPOSITION
? pos
: id
,
2706 flags
& ~MF_REMOVE
);
2707 /* Default: MF_INSERT */
2708 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
2712 /*******************************************************************
2713 * ChangeMenu32A (USER32.23)
2715 BOOL32 WINAPI
ChangeMenu32A( HMENU32 hMenu
, UINT32 pos
, LPCSTR data
,
2716 UINT32 id
, UINT32 flags
)
2718 TRACE(menu
,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2719 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2720 if (flags
& MF_APPEND
) return AppendMenu32A( hMenu
, flags
& ~MF_APPEND
,
2722 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2723 if (flags
& MF_CHANGE
) return ModifyMenu32A(hMenu
, pos
, flags
& ~MF_CHANGE
,
2725 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2726 flags
& MF_BYPOSITION
? pos
: id
,
2727 flags
& ~MF_REMOVE
);
2728 /* Default: MF_INSERT */
2729 return InsertMenu32A( hMenu
, pos
, flags
, id
, data
);
2733 /*******************************************************************
2734 * ChangeMenu32W (USER32.24)
2736 BOOL32 WINAPI
ChangeMenu32W( HMENU32 hMenu
, UINT32 pos
, LPCWSTR data
,
2737 UINT32 id
, UINT32 flags
)
2739 TRACE(menu
,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2740 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2741 if (flags
& MF_APPEND
) return AppendMenu32W( hMenu
, flags
& ~MF_APPEND
,
2743 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2744 if (flags
& MF_CHANGE
) return ModifyMenu32W(hMenu
, pos
, flags
& ~MF_CHANGE
,
2746 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2747 flags
& MF_BYPOSITION
? pos
: id
,
2748 flags
& ~MF_REMOVE
);
2749 /* Default: MF_INSERT */
2750 return InsertMenu32W( hMenu
, pos
, flags
, id
, data
);
2754 /*******************************************************************
2755 * CheckMenuItem16 (USER.154)
2757 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
2759 return (BOOL16
)CheckMenuItem32( hMenu
, id
, flags
);
2763 /*******************************************************************
2764 * CheckMenuItem32 (USER32.46)
2766 DWORD WINAPI
CheckMenuItem32( HMENU32 hMenu
, UINT32 id
, UINT32 flags
)
2771 TRACE(menu
,"%04x %04x %04x\n", hMenu
, id
, flags
);
2772 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
2773 ret
= item
->fState
& MF_CHECKED
;
2774 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
2775 else item
->fState
&= ~MF_CHECKED
;
2780 /**********************************************************************
2781 * EnableMenuItem16 (USER.155)
2783 BOOL16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2785 return EnableMenuItem32( hMenu
, wItemID
, wFlags
);
2789 /**********************************************************************
2790 * EnableMenuItem32 (USER32.170)
2792 BOOL32 WINAPI
EnableMenuItem32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2794 BOOL32 bRet
= FALSE
;
2795 MENUITEM
*item
, *first
= NULL
;
2797 TRACE(menu
,"(%04x, %04X, %04X) !\n",
2798 hMenu
, wItemID
, wFlags
);
2800 while( (item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)) )
2802 if( !(item
->fType
& MF_POPUP
) )
2804 /* We can't have MF_GRAYED and MF_DISABLED together */
2805 if (wFlags
& MF_GRAYED
)
2807 item
->fState
= (item
->fState
& ~MF_DISABLED
) | MF_GRAYED
;
2809 else if (wFlags
& MF_DISABLED
)
2811 item
->fState
= (item
->fState
& ~MF_GRAYED
) | MF_DISABLED
;
2813 else /* MF_ENABLED */
2815 item
->fState
&= ~(MF_GRAYED
| MF_DISABLED
);
2820 if( !first
) first
= item
;
2821 else if( first
== item
) break;
2827 /*******************************************************************
2828 * GetMenuString16 (USER.161)
2830 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
2831 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
2833 return GetMenuString32A( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2837 /*******************************************************************
2838 * GetMenuString32A (USER32.268)
2840 INT32 WINAPI
GetMenuString32A( HMENU32 hMenu
, UINT32 wItemID
,
2841 LPSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2845 TRACE(menu
, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2846 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2847 if (!str
|| !nMaxSiz
) return 0;
2849 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2850 if (!IS_STRING_ITEM(item
->fType
)) return 0;
2851 lstrcpyn32A( str
, item
->text
, nMaxSiz
);
2852 TRACE(menu
, "returning '%s'\n", str
);
2857 /*******************************************************************
2858 * GetMenuString32W (USER32.269)
2860 INT32 WINAPI
GetMenuString32W( HMENU32 hMenu
, UINT32 wItemID
,
2861 LPWSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2865 TRACE(menu
, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2866 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2867 if (!str
|| !nMaxSiz
) return 0;
2869 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2870 if (!IS_STRING_ITEM(item
->fType
)) return 0;
2871 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
2872 return lstrlen32W(str
);
2876 /**********************************************************************
2877 * HiliteMenuItem16 (USER.162)
2879 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
2882 return HiliteMenuItem32( hWnd
, hMenu
, wItemID
, wHilite
);
2886 /**********************************************************************
2887 * HiliteMenuItem32 (USER32.318)
2889 BOOL32 WINAPI
HiliteMenuItem32( HWND32 hWnd
, HMENU32 hMenu
, UINT32 wItemID
,
2893 TRACE(menu
,"(%04x, %04x, %04x, %04x);\n",
2894 hWnd
, hMenu
, wItemID
, wHilite
);
2895 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
2896 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2897 if (menu
->FocusedItem
== wItemID
) return TRUE
;
2898 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
2899 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
2904 /**********************************************************************
2905 * GetMenuState16 (USER.250)
2907 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2909 return GetMenuState32( hMenu
, wItemID
, wFlags
);
2913 /**********************************************************************
2914 * GetMenuState32 (USER32.267)
2916 UINT32 WINAPI
GetMenuState32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2919 TRACE(menu
,"(%04x, %04x, %04x);\n",
2920 hMenu
, wItemID
, wFlags
);
2921 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
2922 debug_print_menuitem (" item: ", item
, "");
2923 if (item
->fType
& MF_POPUP
)
2925 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( item
->hSubMenu
);
2926 if (!menu
) return -1;
2927 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
2931 /* We used to (from way back then) mask the result to 0xff. */
2932 /* I don't know why and it seems wrong as the documented */
2933 /* return flag MF_SEPARATOR is outside that mask. */
2934 return (item
->fType
| item
->fState
);
2939 /**********************************************************************
2940 * GetMenuItemCount16 (USER.263)
2942 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
2944 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2945 if (!IS_A_MENU(menu
)) return -1;
2946 TRACE(menu
,"(%04x) returning %d\n",
2947 hMenu
, menu
->nItems
);
2948 return menu
->nItems
;
2952 /**********************************************************************
2953 * GetMenuItemCount32 (USER32.262)
2955 INT32 WINAPI
GetMenuItemCount32( HMENU32 hMenu
)
2957 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2958 if (!IS_A_MENU(menu
)) return -1;
2959 TRACE(menu
,"(%04x) returning %d\n",
2960 hMenu
, menu
->nItems
);
2961 return menu
->nItems
;
2965 /**********************************************************************
2966 * GetMenuItemID16 (USER.264)
2968 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
2972 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2973 if ((nPos
< 0) || ((UINT16
) nPos
>= menu
->nItems
)) return -1;
2974 if (menu
->items
[nPos
].fType
& MF_POPUP
) return -1;
2975 return menu
->items
[nPos
].wID
;
2979 /**********************************************************************
2980 * GetMenuItemID32 (USER32.263)
2982 UINT32 WINAPI
GetMenuItemID32( HMENU32 hMenu
, INT32 nPos
)
2986 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2987 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2988 return menu
->items
[nPos
].wID
;
2992 /*******************************************************************
2993 * InsertMenu16 (USER.410)
2995 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2996 UINT16 id
, SEGPTR data
)
2998 UINT32 pos32
= (UINT32
)pos
;
2999 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT32
)-1;
3000 if (IS_STRING_ITEM(flags
) && data
)
3001 return InsertMenu32A( hMenu
, pos32
, flags
, id
,
3002 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3003 return InsertMenu32A( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3007 /*******************************************************************
3008 * InsertMenu32A (USER32.322)
3010 BOOL32 WINAPI
InsertMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
3011 UINT32 id
, LPCSTR str
)
3015 if (IS_STRING_ITEM(flags
) && str
)
3016 TRACE(menu
, "hMenu %04x, pos %d, flags %08x, "
3017 "id %04x, str '%s'\n",
3018 hMenu
, pos
, flags
, id
, str
);
3019 else TRACE(menu
, "hMenu %04x, pos %d, flags %08x, "
3020 "id %04x, str %08lx (not a string)\n",
3021 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3023 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3025 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3027 RemoveMenu32( hMenu
, pos
, flags
);
3031 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3032 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3034 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3035 item
->dwItemData
= 0;
3040 /*******************************************************************
3041 * InsertMenu32W (USER32.325)
3043 BOOL32 WINAPI
InsertMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
3044 UINT32 id
, LPCWSTR str
)
3048 if (IS_STRING_ITEM(flags
) && str
)
3050 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3051 ret
= InsertMenu32A( hMenu
, pos
, flags
, id
, newstr
);
3052 HeapFree( GetProcessHeap(), 0, newstr
);
3055 else return InsertMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3059 /*******************************************************************
3060 * AppendMenu16 (USER.411)
3062 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3064 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3068 /*******************************************************************
3069 * AppendMenu32A (USER32.5)
3071 BOOL32 WINAPI
AppendMenu32A( HMENU32 hMenu
, UINT32 flags
,
3072 UINT32 id
, LPCSTR data
)
3074 return InsertMenu32A( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3078 /*******************************************************************
3079 * AppendMenu32W (USER32.6)
3081 BOOL32 WINAPI
AppendMenu32W( HMENU32 hMenu
, UINT32 flags
,
3082 UINT32 id
, LPCWSTR data
)
3084 return InsertMenu32W( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3088 /**********************************************************************
3089 * RemoveMenu16 (USER.412)
3091 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3093 return RemoveMenu32( hMenu
, nPos
, wFlags
);
3097 /**********************************************************************
3098 * RemoveMenu32 (USER32.441)
3100 BOOL32 WINAPI
RemoveMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
3105 TRACE(menu
,"(%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
3106 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3107 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3111 MENU_FreeItemData( item
);
3113 if (--menu
->nItems
== 0)
3115 HeapFree( SystemHeap
, 0, menu
->items
);
3120 while(nPos
< menu
->nItems
)
3126 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3127 menu
->nItems
* sizeof(MENUITEM
) );
3133 /**********************************************************************
3134 * DeleteMenu16 (USER.413)
3136 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3138 return DeleteMenu32( hMenu
, nPos
, wFlags
);
3142 /**********************************************************************
3143 * DeleteMenu32 (USER32.129)
3145 BOOL32 WINAPI
DeleteMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
3147 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3148 if (!item
) return FALSE
;
3149 if (item
->fType
& MF_POPUP
) DestroyMenu32( item
->hSubMenu
);
3150 /* nPos is now the position of the item */
3151 RemoveMenu32( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3156 /*******************************************************************
3157 * ModifyMenu16 (USER.414)
3159 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3160 UINT16 id
, SEGPTR data
)
3162 if (IS_STRING_ITEM(flags
))
3163 return ModifyMenu32A( hMenu
, pos
, flags
, id
,
3164 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3165 return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3169 /*******************************************************************
3170 * ModifyMenu32A (USER32.397)
3172 BOOL32 WINAPI
ModifyMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
3173 UINT32 id
, LPCSTR str
)
3177 if (IS_STRING_ITEM(flags
))
3179 TRACE(menu
, "%04x %d %04x %04x '%s'\n",
3180 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3181 if (!str
) return FALSE
;
3185 TRACE(menu
, "%04x %d %04x %04x %08lx\n",
3186 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3189 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3190 return MENU_SetItemData( item
, flags
, id
, str
);
3194 /*******************************************************************
3195 * ModifyMenu32W (USER32.398)
3197 BOOL32 WINAPI
ModifyMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
3198 UINT32 id
, LPCWSTR str
)
3202 if (IS_STRING_ITEM(flags
) && str
)
3204 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3205 ret
= ModifyMenu32A( hMenu
, pos
, flags
, id
, newstr
);
3206 HeapFree( GetProcessHeap(), 0, newstr
);
3209 else return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3213 /**********************************************************************
3214 * CreatePopupMenu16 (USER.415)
3216 HMENU16 WINAPI
CreatePopupMenu16(void)
3218 return CreatePopupMenu32();
3222 /**********************************************************************
3223 * CreatePopupMenu32 (USER32.82)
3225 HMENU32 WINAPI
CreatePopupMenu32(void)
3230 if (!(hmenu
= CreateMenu32())) return 0;
3231 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3232 menu
->wFlags
|= MF_POPUP
;
3237 /**********************************************************************
3238 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3240 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3242 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3246 /**********************************************************************
3247 * SetMenuItemBitmaps16 (USER.418)
3249 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3250 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3252 return SetMenuItemBitmaps32( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3256 /**********************************************************************
3257 * SetMenuItemBitmaps32 (USER32.490)
3259 BOOL32 WINAPI
SetMenuItemBitmaps32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
,
3260 HBITMAP32 hNewUnCheck
, HBITMAP32 hNewCheck
)
3263 TRACE(menu
,"(%04x, %04x, %04x, %04x, %04x)\n",
3264 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3265 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3267 if (!hNewCheck
&& !hNewUnCheck
)
3269 item
->fState
&= ~MF_USECHECKBITMAPS
;
3271 else /* Install new bitmaps */
3273 item
->hCheckBit
= hNewCheck
;
3274 item
->hUnCheckBit
= hNewUnCheck
;
3275 item
->fState
|= MF_USECHECKBITMAPS
;
3281 /**********************************************************************
3282 * CreateMenu16 (USER.151)
3284 HMENU16 WINAPI
CreateMenu16(void)
3286 return CreateMenu32();
3290 /**********************************************************************
3291 * CreateMenu32 (USER32.81)
3293 HMENU32 WINAPI
CreateMenu32(void)
3297 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3298 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3300 menu
->wMagic
= MENU_MAGIC
;
3307 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3308 TRACE(menu
, "return %04x\n", hMenu
);
3313 /**********************************************************************
3314 * DestroyMenu16 (USER.152)
3316 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3318 return DestroyMenu32( hMenu
);
3322 /**********************************************************************
3323 * DestroyMenu32 (USER32.134)
3325 BOOL32 WINAPI
DestroyMenu32( HMENU32 hMenu
)
3327 TRACE(menu
,"(%04x)\n", hMenu
);
3329 /* Silently ignore attempts to destroy default system popup */
3331 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3333 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3335 if( pTopPopupWnd
&& (hMenu
== *(HMENU32
*)pTopPopupWnd
->wExtra
) )
3336 *(UINT32
*)pTopPopupWnd
->wExtra
= 0;
3338 if (IS_A_MENU( lppop
))
3340 lppop
->wMagic
= 0; /* Mark it as destroyed */
3342 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3343 (!pTopPopupWnd
|| (lppop
->hWnd
!= pTopPopupWnd
->hwndSelf
)))
3344 DestroyWindow32( lppop
->hWnd
);
3346 if (lppop
->items
) /* recursively destroy submenus */
3349 MENUITEM
*item
= lppop
->items
;
3350 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3352 if (item
->fType
& MF_POPUP
) DestroyMenu32(item
->hSubMenu
);
3353 MENU_FreeItemData( item
);
3355 HeapFree( SystemHeap
, 0, lppop
->items
);
3357 USER_HEAP_FREE( hMenu
);
3361 return (hMenu
!= MENU_DefSysPopup
);
3365 /**********************************************************************
3366 * GetSystemMenu16 (USER.156)
3368 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3370 return GetSystemMenu32( hWnd
, bRevert
);
3374 /**********************************************************************
3375 * GetSystemMenu32 (USER32.291)
3377 HMENU32 WINAPI
GetSystemMenu32( HWND32 hWnd
, BOOL32 bRevert
)
3379 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3383 if( wndPtr
->hSysMenu
)
3387 DestroyMenu32(wndPtr
->hSysMenu
);
3388 wndPtr
->hSysMenu
= 0;
3392 POPUPMENU
*menu
= (POPUPMENU
*)
3393 USER_HEAP_LIN_ADDR(wndPtr
->hSysMenu
);
3394 if( menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3395 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3399 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3400 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU32
)(-1) );
3402 if( wndPtr
->hSysMenu
)
3403 return GetSubMenu16(wndPtr
->hSysMenu
, 0);
3409 /*******************************************************************
3410 * SetSystemMenu16 (USER.280)
3412 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3414 return SetSystemMenu32( hwnd
, hMenu
);
3418 /*******************************************************************
3419 * SetSystemMenu32 (USER32.508)
3421 BOOL32 WINAPI
SetSystemMenu32( HWND32 hwnd
, HMENU32 hMenu
)
3423 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3427 if (wndPtr
->hSysMenu
) DestroyMenu32( wndPtr
->hSysMenu
);
3428 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3435 /**********************************************************************
3436 * GetMenu16 (USER.157)
3438 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
3440 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3441 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3442 return (HMENU16
)wndPtr
->wIDmenu
;
3447 /**********************************************************************
3448 * GetMenu32 (USER32.257)
3450 HMENU32 WINAPI
GetMenu32( HWND32 hWnd
)
3452 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3453 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3454 return (HMENU32
)wndPtr
->wIDmenu
;
3459 /**********************************************************************
3460 * SetMenu16 (USER.158)
3462 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
3464 return SetMenu32( hWnd
, hMenu
);
3468 /**********************************************************************
3469 * SetMenu32 (USER32.487)
3471 BOOL32 WINAPI
SetMenu32( HWND32 hWnd
, HMENU32 hMenu
)
3473 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3475 TRACE(menu
,"(%04x, %04x);\n", hWnd
, hMenu
);
3477 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3479 if (GetCapture32() == hWnd
) ReleaseCapture();
3481 wndPtr
->wIDmenu
= (UINT32
)hMenu
;
3486 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3487 lpmenu
->hWnd
= hWnd
;
3488 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
3489 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3491 if (IsWindowVisible32(hWnd
))
3492 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3493 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3501 /**********************************************************************
3502 * GetSubMenu16 (USER.159)
3504 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3506 return GetSubMenu32( hMenu
, nPos
);
3510 /**********************************************************************
3511 * GetSubMenu32 (USER32.288)
3513 HMENU32 WINAPI
GetSubMenu32( HMENU32 hMenu
, INT32 nPos
)
3517 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
3518 if ((UINT32
)nPos
>= lppop
->nItems
) return 0;
3519 if (!(lppop
->items
[nPos
].fType
& MF_POPUP
)) return 0;
3520 return lppop
->items
[nPos
].hSubMenu
;
3524 /**********************************************************************
3525 * DrawMenuBar16 (USER.160)
3527 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
3529 DrawMenuBar32( hWnd
);
3533 /**********************************************************************
3534 * DrawMenuBar32 (USER32.161)
3536 BOOL32 WINAPI
DrawMenuBar32( HWND32 hWnd
)
3539 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
3540 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
3542 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
3543 if (lppop
== NULL
) return FALSE
;
3545 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3546 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3547 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3554 /***********************************************************************
3555 * EndMenu (USER.187) (USER32.175)
3557 void WINAPI
EndMenu(void)
3563 /***********************************************************************
3564 * LookupMenuHandle (USER.217)
3566 HMENU16 WINAPI
LookupMenuHandle( HMENU16 hmenu
, INT16 id
)
3568 HMENU32 hmenu32
= hmenu
;
3570 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
3571 else return hmenu32
;
3575 /**********************************************************************
3576 * LoadMenu16 (USER.150)
3578 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
3586 char *str
= (char *)PTR_SEG_TO_LIN( name
);
3587 TRACE(menu
, "(%04x,'%s')\n", instance
, str
);
3588 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
3591 TRACE(resource
,"(%04x,%04x)\n",instance
,LOWORD(name
));
3593 if (!name
) return 0;
3595 /* check for Win32 module */
3596 if (HIWORD(instance
))
3597 return LoadMenu32A(instance
,PTR_SEG_TO_LIN(name
));
3598 instance
= GetExePtr( instance
);
3600 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
3601 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
3602 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
3603 FreeResource16( handle
);
3608 /*****************************************************************
3609 * LoadMenu32A (USER32.370)
3611 HMENU32 WINAPI
LoadMenu32A( HINSTANCE32 instance
, LPCSTR name
)
3613 HRSRC32 hrsrc
= FindResource32A( instance
, name
, RT_MENU32A
);
3614 if (!hrsrc
) return 0;
3615 return LoadMenuIndirect32A( (LPCVOID
)LoadResource32( instance
, hrsrc
));
3619 /*****************************************************************
3620 * LoadMenu32W (USER32.373)
3622 HMENU32 WINAPI
LoadMenu32W( HINSTANCE32 instance
, LPCWSTR name
)
3624 HRSRC32 hrsrc
= FindResource32W( instance
, name
, RT_MENU32W
);
3625 if (!hrsrc
) return 0;
3626 return LoadMenuIndirect32W( (LPCVOID
)LoadResource32( instance
, hrsrc
));
3630 /**********************************************************************
3631 * LoadMenuIndirect16 (USER.220)
3633 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
3636 WORD version
, offset
;
3637 LPCSTR p
= (LPCSTR
)template;
3639 TRACE(menu
,"(%p)\n", template );
3640 version
= GET_WORD(p
);
3644 WARN(menu
, "version must be 0 for Win16\n" );
3647 offset
= GET_WORD(p
);
3648 p
+= sizeof(WORD
) + offset
;
3649 if (!(hMenu
= CreateMenu32())) return 0;
3650 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
3652 DestroyMenu32( hMenu
);
3659 /**********************************************************************
3660 * LoadMenuIndirect32A (USER32.371)
3662 HMENU32 WINAPI
LoadMenuIndirect32A( LPCVOID
template )
3665 WORD version
, offset
;
3666 LPCSTR p
= (LPCSTR
)template;
3668 TRACE(menu
,"%p\n", template );
3669 version
= GET_WORD(p
);
3674 offset
= GET_WORD(p
);
3675 p
+= sizeof(WORD
) + offset
;
3676 if (!(hMenu
= CreateMenu32())) return 0;
3677 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
3679 DestroyMenu32( hMenu
);
3684 offset
= GET_WORD(p
);
3685 p
+= sizeof(WORD
) + offset
;
3686 if (!(hMenu
= CreateMenu32())) return 0;
3687 if (!MENUEX_ParseResource( p
, hMenu
))
3689 DestroyMenu32( hMenu
);
3694 ERR(menu
, "version %d not supported.\n", version
);
3700 /**********************************************************************
3701 * LoadMenuIndirect32W (USER32.372)
3703 HMENU32 WINAPI
LoadMenuIndirect32W( LPCVOID
template )
3705 /* FIXME: is there anything different between A and W? */
3706 return LoadMenuIndirect32A( template );
3710 /**********************************************************************
3711 * IsMenu16 (USER.358)
3713 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
3715 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
3716 return IS_A_MENU(menu
);
3720 /**********************************************************************
3721 * IsMenu32 (USER32.346)
3723 BOOL32 WINAPI
IsMenu32(HMENU32 hmenu
)
3725 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
3726 return IS_A_MENU(menu
);
3729 /**********************************************************************
3730 * GetMenuItemInfo32_common
3733 static BOOL32
GetMenuItemInfo32_common ( HMENU32 hmenu
, UINT32 item
,
3735 LPMENUITEMINFO32A lpmii
,
3738 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
);
3739 debug_print_menuitem("GetMenuItemInfo32_common: ", menu
, "");
3743 if (lpmii
->fMask
& MIIM_TYPE
) {
3744 lpmii
->fType
= menu
->fType
;
3745 switch (MENU_ITEM_TYPE(menu
->fType
)) {
3747 if (menu
->text
&& lpmii
->dwTypeData
&& lpmii
->cch
) {
3749 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
,
3753 lstrcpyn32A(lpmii
->dwTypeData
,
3760 lpmii
->dwTypeData
= menu
->text
;
3766 if (lpmii
->fMask
& MIIM_STATE
)
3767 lpmii
->fState
= menu
->fState
;
3769 if (lpmii
->fMask
& MIIM_ID
)
3770 lpmii
->wID
= menu
->wID
;
3772 if (lpmii
->fMask
& MIIM_SUBMENU
)
3773 lpmii
->hSubMenu
= menu
->hSubMenu
;
3775 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
3776 lpmii
->hbmpChecked
= menu
->hCheckBit
;
3777 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
3779 if (lpmii
->fMask
& MIIM_DATA
)
3780 lpmii
->dwItemData
= menu
->dwItemData
;
3785 /**********************************************************************
3786 * GetMenuItemInfo32A (USER32.264)
3788 BOOL32 WINAPI
GetMenuItemInfo32A( HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3789 LPMENUITEMINFO32A lpmii
)
3791 return GetMenuItemInfo32_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
3794 /**********************************************************************
3795 * GetMenuItemInfo32W (USER32.265)
3797 BOOL32 WINAPI
GetMenuItemInfo32W( HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3798 LPMENUITEMINFO32W lpmii
)
3800 return GetMenuItemInfo32_common (hmenu
, item
, bypos
,
3801 (LPMENUITEMINFO32A
)lpmii
, TRUE
);
3804 /**********************************************************************
3805 * SetMenuItemInfo32_common
3808 static BOOL32
SetMenuItemInfo32_common(MENUITEM
* menu
,
3809 const MENUITEMINFO32A
*lpmii
,
3812 if (!menu
) return FALSE
;
3814 if (lpmii
->fMask
& MIIM_TYPE
) {
3815 /* Get rid of old string. */
3816 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
)
3817 HeapFree(SystemHeap
, 0, menu
->text
);
3819 menu
->fType
= lpmii
->fType
;
3820 menu
->text
= lpmii
->dwTypeData
;
3821 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
3824 ? HEAP_strdupWtoA(SystemHeap
, 0,
3825 (LPWSTR
) lpmii
->dwTypeData
)
3826 : HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
3829 if (lpmii
->fMask
& MIIM_STATE
)
3830 menu
->fState
= lpmii
->fState
;
3832 if (lpmii
->fMask
& MIIM_ID
)
3833 menu
->wID
= lpmii
->wID
;
3835 if (lpmii
->fMask
& MIIM_SUBMENU
)
3836 menu
->hSubMenu
= lpmii
->hSubMenu
;
3838 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
3840 menu
->hCheckBit
= lpmii
->hbmpChecked
;
3841 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
3843 if (lpmii
->fMask
& MIIM_DATA
)
3844 menu
->dwItemData
= lpmii
->dwItemData
;
3846 debug_print_menuitem("SetMenuItemInfo32_common: ", menu
, "");
3850 /**********************************************************************
3851 * SetMenuItemInfo32A (USER32.491)
3853 BOOL32 WINAPI
SetMenuItemInfo32A(HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3854 const MENUITEMINFO32A
*lpmii
)
3856 return SetMenuItemInfo32_common(MENU_FindItem(&hmenu
, &item
, bypos
),
3860 /**********************************************************************
3861 * SetMenuItemInfo32W (USER32.492)
3863 BOOL32 WINAPI
SetMenuItemInfo32W(HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3864 const MENUITEMINFO32W
*lpmii
)
3866 return SetMenuItemInfo32_common(MENU_FindItem(&hmenu
, &item
, bypos
),
3867 (const MENUITEMINFO32A
*)lpmii
, TRUE
);
3870 /**********************************************************************
3871 * SetMenuDefaultItem32 (USER32.489)
3873 BOOL32 WINAPI
SetMenuDefaultItem32(HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
)
3875 MENUITEM
*menu
= MENU_FindItem(&hmenu
, &item
, bypos
);
3876 if (!menu
) return FALSE
;
3877 debug_print_menuitem("SetMenuDefaultItem32: ", menu
, "");
3878 FIXME(menu
, "(0x%x,%d,%d), empty stub!\n",
3879 hmenu
, item
, bypos
);
3883 /*******************************************************************
3884 * InsertMenuItem16 (USER.441)
3888 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
3889 const MENUITEMINFO16
*mii
)
3891 MENUITEMINFO32A miia
;
3893 miia
.cbSize
= sizeof(miia
);
3894 miia
.fMask
= mii
->fMask
;
3895 miia
.dwTypeData
= mii
->dwTypeData
;
3896 miia
.fType
= mii
->fType
;
3897 miia
.fState
= mii
->fState
;
3898 miia
.wID
= mii
->wID
;
3899 miia
.hSubMenu
= mii
->hSubMenu
;
3900 miia
.hbmpChecked
= mii
->hbmpChecked
;
3901 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
3902 miia
.dwItemData
= mii
->dwItemData
;
3903 miia
.cch
= mii
->cch
;
3904 if (IS_STRING_ITEM(miia
.fType
))
3905 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
3906 return InsertMenuItem32A( hmenu
, pos
, byposition
, &miia
);
3910 /**********************************************************************
3911 * InsertMenuItem32A (USER32.323)
3913 BOOL32 WINAPI
InsertMenuItem32A(HMENU32 hMenu
, UINT32 uItem
, BOOL32 bypos
,
3914 const MENUITEMINFO32A
*lpmii
)
3916 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
3917 return SetMenuItemInfo32_common(item
, lpmii
, FALSE
);
3921 /**********************************************************************
3922 * InsertMenuItem32W (USER32.324)
3924 BOOL32 WINAPI
InsertMenuItem32W(HMENU32 hMenu
, UINT32 uItem
, BOOL32 bypos
,
3925 const MENUITEMINFO32W
*lpmii
)
3927 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
3928 return SetMenuItemInfo32_common(item
, (const MENUITEMINFO32A
*)lpmii
, TRUE
);
3931 /**********************************************************************
3932 * CheckMenuRadioItem32 (USER32.47)
3935 BOOL32 WINAPI
CheckMenuRadioItem32(HMENU32 hMenu
,
3936 UINT32 first
, UINT32 last
, UINT32 check
,
3939 MENUITEM
*mifirst
, *milast
, *micheck
;
3940 HMENU32 mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
3942 TRACE(menu
, "ox%x: %d-%d, check %d, bypos=%d\n",
3943 hMenu
, first
, last
, check
, bypos
);
3945 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
3946 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
3947 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
3949 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
3950 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
3951 micheck
> milast
|| micheck
< mifirst
)
3954 while (mifirst
<= milast
)
3956 if (mifirst
== micheck
)
3958 mifirst
->fType
|= MFT_RADIOCHECK
;
3959 mifirst
->fState
|= MFS_CHECKED
;
3961 mifirst
->fType
&= ~MFT_RADIOCHECK
;
3962 mifirst
->fState
&= ~MFS_CHECKED
;
3970 /**********************************************************************
3971 * CheckMenuRadioItem16 (not a Windows API)
3974 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
3975 UINT16 first
, UINT16 last
, UINT16 check
,
3978 return CheckMenuRadioItem32 (hMenu
, first
, last
, check
, bypos
);
3981 /**********************************************************************
3982 * GetMenuItemRect32 (USER32.266)
3985 BOOL32 WINAPI
GetMenuItemRect32 (HWND32 hwnd
, HMENU32 hMenu
, UINT32 uItem
,
3988 RECT32 saverect
, clientrect
;
3993 HMENU32 orghMenu
= hMenu
;
3995 TRACE(menu
, "(0x%x,0x%x,%d,%p)\n",
3996 hwnd
, hMenu
, uItem
, rect
);
3998 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
3999 wndPtr
= WIN_FindWndPtr (hwnd
);
4000 if (!rect
|| !item
|| !wndPtr
) return FALSE
;
4002 GetClientRect32( hwnd
, &clientrect
);
4003 hdc
= GetDCEx32( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
4004 barp
= (hMenu
== orghMenu
);
4006 saverect
= item
->rect
;
4007 MENU_CalcItemSize (hdc
, item
, hwnd
,
4008 clientrect
.left
, clientrect
.top
, barp
);
4010 item
->rect
= saverect
;
4012 ReleaseDC32( hwnd
, hdc
);
4016 /**********************************************************************
4017 * GetMenuItemRect16 (USER.665)
4020 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4026 if (!rect
) return FALSE
;
4027 res
= GetMenuItemRect32 (hwnd
, hMenu
, uItem
, &r32
);
4028 CONV_RECT32TO16 (&r32
, rect
);