2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: user32/windows/menu.c
7 * PROGRAMMERS: Casper S. Hornstrup
11 /* INCLUDES ******************************************************************/
14 #include <wine/debug.h>
16 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
18 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
20 /* internal popup menu window messages */
22 #define MM_SETMENUHANDLE (WM_USER + 0)
23 #define MM_GETMENUHANDLE (WM_USER + 1)
25 /* internal flags for menu tracking */
27 #define TF_ENDMENU 0x10000
28 #define TF_SUSPENDPOPUP 0x20000
29 #define TF_SKIPREMOVE 0x40000
34 /* Internal MenuTrackMenu() flags */
35 #define TPM_INTERNAL 0xF0000000
36 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
37 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
40 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
42 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
44 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
45 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
46 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
48 #define IS_SYSTEM_MENU(MenuInfo) \
49 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
51 #define IS_SYSTEM_POPUP(MenuInfo) \
52 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
54 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
56 /* Use global popup window because there's no way 2 menus can
57 * be tracked at the same time. */
58 static HWND top_popup
;
59 static HMENU top_popup_hmenu
;
61 /* Flag set by EndMenu() to force an exit from menu tracking */
62 static BOOL fEndMenu
= FALSE
;
64 #define MENU_ITEM_HBMP_SPACE (5)
65 #define MENU_BAR_ITEMS_SPACE (12)
66 #define SEPARATOR_HEIGHT (5)
67 #define MENU_TAB_SPACE (8)
72 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
73 HMENU TopMenu
; /* initial menu */
74 HWND OwnerWnd
; /* where notifications are sent */
79 /*********************************************************************
80 * PopupMenu class descriptor
82 const struct builtin_class_descr POPUPMENU_builtin_class
=
85 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
86 (WNDPROC
) NULL
, /* FIXME - procA */
87 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
88 sizeof(MENUINFO
*), /* extra */
89 (LPCWSTR
) IDC_ARROW
, /* cursor */
90 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
94 #define GET_WORD(ptr) (*(WORD *)(ptr))
97 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
100 HFONT hMenuFont
= NULL
;
101 HFONT hMenuFontBold
= NULL
;
103 /* Dimension of the menu bitmaps */
104 static HBITMAP BmpSysMenu
= NULL
;
106 static SIZE MenuCharSize
;
108 /***********************************************************************
111 * Get full information about menu
114 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
116 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
117 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
119 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
122 /***********************************************************************
125 * Set full information about menu
128 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
130 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
131 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
133 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
136 /***********************************************************************
137 * MenuInitRosMenuItemInfo
139 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
142 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
144 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
145 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
148 /***********************************************************************
149 * MenuGetRosMenuItemInfo
151 * Get full information about a menu item
154 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
156 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
158 if (ItemInfo
->dwTypeData
!= NULL
)
160 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
164 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
165 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
166 ItemInfo
->dwTypeData
= NULL
;
168 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
174 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
177 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
178 ItemInfo
->cch
* sizeof(WCHAR
));
179 if (NULL
== ItemInfo
->dwTypeData
)
184 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
189 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
191 ItemInfo
->fMask
= Save_Mask
;
195 /***********************************************************************
196 * MenuSetRosMenuItemInfo
198 * Set selected information about a menu item, need to set the mask bits.
201 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
205 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
206 ItemInfo
->dwTypeData
!= NULL
)
208 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
210 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
215 /***********************************************************************
216 * MenuCleanupRosMenuItemInfo
218 * Cleanup after use of MenuGet/SetRosMenuItemInfo
221 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
223 if (ItemInfo
->dwTypeData
!= NULL
)
225 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
226 ItemInfo
->dwTypeData
= NULL
;
230 /***********************************************************************
231 * MenuGetAllRosMenuItemInfo
233 * Get full information about all menu items
236 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
240 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
241 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
245 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
246 if (NULL
== *ItemInfo
)
251 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
254 /***********************************************************************
255 * MenuCleanupAllRosMenuItemInfo
257 * Cleanup after use of MenuGetAllRosMenuItemInfo
260 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
262 HeapFree(GetProcessHeap(), 0, ItemInfo
);
265 /***********************************************************************
266 * MenuInitSysMenuPopup
268 * Grey the appropriate items in System menu.
270 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
278 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
279 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
280 gray
= ((style
& WS_MAXIMIZE
) != 0);
281 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
282 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
283 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
284 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
285 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
286 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
287 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
288 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
290 /* The menu item must keep its state if it's disabled */
292 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
294 /* Set default menu item */
295 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
296 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
297 else DefItem
= SC_CLOSE
;
299 mii
.cbSize
= sizeof(MENUITEMINFOW
);
300 mii
.fMask
|= MIIM_STATE
;
301 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
302 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
304 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
307 /******************************************************************************
309 * UINT MenuGetStartOfNextColumn(
310 * PROSMENUINFO MenuInfo)
312 *****************************************************************************/
313 static UINT
MenuGetStartOfNextColumn(
314 PROSMENUINFO MenuInfo
)
316 PROSMENUITEMINFO MenuItems
;
319 i
= MenuInfo
->FocusedItem
;
320 if ( i
== NO_SELECTED_ITEM
)
323 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
324 return NO_SELECTED_ITEM
;
326 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
327 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
330 return NO_SELECTED_ITEM
;
333 /******************************************************************************
335 * UINT MenuGetStartOfPrevColumn(
336 * PROSMENUINFO MenuInfo)
338 *****************************************************************************/
340 static UINT FASTCALL
MenuGetStartOfPrevColumn(
341 PROSMENUINFO MenuInfo
)
343 PROSMENUITEMINFO MenuItems
;
346 if (!MenuInfo
->FocusedItem
|| MenuInfo
->FocusedItem
== NO_SELECTED_ITEM
)
347 return NO_SELECTED_ITEM
;
349 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
350 return NO_SELECTED_ITEM
;
352 /* Find the start of the column */
353 for (i
= MenuInfo
->FocusedItem
;
354 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
362 MenuCleanupAllRosMenuItemInfo(MenuItems
);
363 return NO_SELECTED_ITEM
;
366 for (--i
; 0 != i
; --i
)
367 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
370 MenuCleanupAllRosMenuItemInfo(MenuItems
);
371 TRACE("ret %d.\n", i
);
376 /***********************************************************************
379 * Find a Sub menu. Return the position of the submenu, and modifies
380 * *hmenu in case it is found in another sub-menu.
381 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
383 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
387 ROSMENUITEMINFO item
;
388 if (((*hmenu
)==(HMENU
)0xffff) ||
389 (!MenuGetRosMenuInfo(&menu
, *hmenu
)))
390 return NO_SELECTED_ITEM
;
392 MenuInitRosMenuItemInfo(&item
);
393 for (i
= 0; i
< menu
.MenuItemCount
; i
++) {
394 if (! MenuGetRosMenuItemInfo(menu
.Self
, i
, &item
))
396 MenuCleanupRosMenuItemInfo(&item
);
397 return NO_SELECTED_ITEM
;
399 if (!(item
.fType
& MF_POPUP
)) continue;
400 if (item
.hSubMenu
== hSubTarget
) {
401 MenuCleanupRosMenuItemInfo(&item
);
405 HMENU hsubmenu
= item
.hSubMenu
;
406 UINT pos
= MenuFindSubMenu(&hsubmenu
, hSubTarget
);
407 if (pos
!= NO_SELECTED_ITEM
) {
413 MenuCleanupRosMenuItemInfo(&item
);
414 return NO_SELECTED_ITEM
;
417 /***********************************************************************
420 * Load the arrow bitmap. We can't do this from MenuInit since user32
421 * can also be used (and thus initialized) from text-mode.
424 MenuLoadBitmaps(VOID
)
426 /* Load system buttons bitmaps */
427 if (NULL
== BmpSysMenu
)
429 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
433 /***********************************************************************
436 * Draws popup magic glyphs (can be found in system menu).
439 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
442 HFONT hFont
, hOldFont
;
448 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
451 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
454 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
457 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
461 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
464 ZeroMemory(&lf
, sizeof(LOGFONTW
));
465 InflateRect(r
, -2, -2);
466 lf
.lfHeight
= r
->bottom
- r
->top
;
468 lf
.lfWeight
= FW_NORMAL
;
469 lf
.lfCharSet
= DEFAULT_CHARSET
;
470 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
471 hFont
= CreateFontIndirect(&lf
);
472 /* save font and text color */
473 hOldFont
= SelectObject(dc
, hFont
);
474 clrsave
= GetTextColor(dc
);
475 bkmode
= GetBkMode(dc
);
476 /* set color and drawing mode */
477 SetBkMode(dc
, TRANSPARENT
);
483 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
484 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
487 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
488 /* draw selected symbol */
489 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
490 /* restore previous settings */
491 SetTextColor(dc
, clrsave
);
492 SelectObject(dc
, hOldFont
);
493 SetBkMode(dc
, bkmode
);
497 /***********************************************************************
500 * Find the menu item selected by a key press.
501 * Return item id, -1 if none, -2 if we should close the menu.
503 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
504 WCHAR Key
, BOOL ForceMenuChar
)
506 ROSMENUINFO SysMenuInfo
;
507 PROSMENUITEMINFO Items
, ItemInfo
;
511 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
513 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
515 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
517 MenuInfo
= &SysMenuInfo
;
525 if (NULL
!= MenuInfo
)
527 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
535 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
537 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
539 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
542 p
= strchrW(p
+ 2, '&');
544 while (NULL
!= p
&& L
'&' == p
[1]);
545 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
553 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
554 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
555 if (2 == HIWORD(MenuChar
))
557 return LOWORD(MenuChar
);
559 if (1 == HIWORD(MenuChar
))
568 /***********************************************************************
569 * MenuGetBitmapItemSize
571 * Get the size of a bitmap item.
573 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
576 HBITMAP bmp
= lpitem
->hbmpItem
;
578 size
->cx
= size
->cy
= 0;
580 /* check if there is a magic menu item associated with this item */
581 if (IS_MAGIC_BITMAP(bmp
))
583 switch((INT_PTR
) bmp
)
585 case (INT_PTR
)HBMMENU_CALLBACK
:
587 MEASUREITEMSTRUCT measItem
;
588 measItem
.CtlType
= ODT_MENU
;
590 measItem
.itemID
= lpitem
->wID
;
591 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
592 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
593 measItem
.itemData
= lpitem
->dwItemData
;
594 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
595 size
->cx
= measItem
.itemWidth
;
596 size
->cy
= measItem
.itemHeight
;
601 case (INT_PTR
) HBMMENU_SYSTEM
:
602 if (0 != lpitem
->dwItemData
)
604 bmp
= (HBITMAP
) lpitem
->dwItemData
;
608 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
609 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
610 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
611 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
612 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
613 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
614 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
615 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
616 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
617 /* FIXME: Why we need to subtract these magic values? */
618 /* to make them smaller than the menu bar? */
619 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
620 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
625 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
627 size
->cx
= bm
.bmWidth
;
628 size
->cy
= bm
.bmHeight
;
632 /***********************************************************************
635 * Draw a bitmap item.
637 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
638 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
644 int w
= rect
->right
- rect
->left
;
645 int h
= rect
->bottom
- rect
->top
;
648 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
651 /* Check if there is a magic menu item associated with this item */
652 if (IS_MAGIC_BITMAP(hbmToDraw
))
658 switch ((INT_PTR
)hbmToDraw
)
660 case (INT_PTR
)HBMMENU_SYSTEM
:
661 if (lpitem
->dwTypeData
)
663 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
664 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
668 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
670 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
671 /* only use right half of the bitmap */
672 bmp_xoffset
= bm
.bmWidth
/ 2;
673 bm
.bmWidth
-= bmp_xoffset
;
676 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
677 flags
= DFCS_CAPTIONRESTORE
;
679 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
681 flags
= DFCS_CAPTIONMIN
;
683 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
685 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
687 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
688 flags
= DFCS_CAPTIONCLOSE
;
690 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
691 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
693 case (INT_PTR
)HBMMENU_CALLBACK
:
695 DRAWITEMSTRUCT drawItem
;
697 drawItem
.CtlType
= ODT_MENU
;
699 drawItem
.itemID
= lpitem
->wID
;
700 drawItem
.itemAction
= odaction
;
701 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
702 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
703 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
704 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
705 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
706 drawItem
.hwndItem
= (HWND
)hmenu
;
708 drawItem
.rcItem
= *rect
;
709 drawItem
.itemData
= lpitem
->dwItemData
;
710 /* some applications make this assumption on the DC's origin */
711 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
712 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
713 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
714 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
719 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
720 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
721 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
722 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
723 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
726 InflateRect(&r
, -1, -1);
727 if (0 != (lpitem
->fState
& MF_HILITE
))
729 flags
|= DFCS_PUSHED
;
731 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
735 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
738 hdcMem
= CreateCompatibleDC( hdc
);
739 SelectObject( hdcMem
, bmp
);
741 /* handle fontsize > bitmap_height */
742 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
744 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
745 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
746 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
747 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
751 /***********************************************************************
754 * Calculate the size of the menu item and store it in lpitem->rect.
756 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
757 INT orgX
, INT orgY
, BOOL menuBar
)
760 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
763 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
765 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
767 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
769 if (lpitem
->fType
& MF_OWNERDRAW
)
771 MEASUREITEMSTRUCT mis
;
772 mis
.CtlType
= ODT_MENU
;
774 mis
.itemID
= lpitem
->wID
;
775 mis
.itemData
= lpitem
->dwItemData
;
776 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
778 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
779 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
780 * width of a menufont character to the width of an owner-drawn menu.
782 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
785 /* under at least win95 you seem to be given a standard
786 height for the menu and the height value is ignored */
787 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
789 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
791 TRACE("id=%04lx size=%dx%d\n",
792 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
796 if (lpitem
->fType
& MF_SEPARATOR
)
798 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
800 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
806 if (lpitem
->hbmpItem
)
811 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
812 /* Keep the size of the bitmap in callback mode to be able
813 * to draw it correctly */
814 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
815 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
816 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
818 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
819 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
821 MenuSetRosMenuInfo(MenuInfo
);
822 itemheight
= size
.cy
+ 2;
824 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
825 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
826 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
827 lpitem
->dxTab
= lpitem
->Rect
.right
;
828 lpitem
->Rect
.right
+= check_bitmap_width
;
829 } else /* hbmpItem & MenuBar */ {
830 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
831 lpitem
->Rect
.right
+= size
.cx
;
832 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
833 itemheight
= size
.cy
;
835 /* Special case: Minimize button doesn't have a space behind it. */
836 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
837 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
838 lpitem
->Rect
.right
-= 1;
842 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
843 lpitem
->Rect
.right
+= check_bitmap_width
;
844 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
845 lpitem
->dxTab
= lpitem
->Rect
.right
;
846 lpitem
->Rect
.right
+= check_bitmap_width
;
849 /* it must be a text item - unless it's the system menu */
850 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
851 HFONT hfontOld
= NULL
;
852 RECT rc
= lpitem
->Rect
;
853 LONG txtheight
, txtwidth
;
855 if ( lpitem
->fState
& MFS_DEFAULT
) {
856 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
859 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
860 DT_SINGLELINE
|DT_CALCRECT
);
861 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
862 itemheight
= max( max( itemheight
, txtheight
),
863 GetSystemMetrics( SM_CYMENU
) - 1);
864 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
866 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
869 int n
= (int)( p
- lpitem
->dwTypeData
);
870 /* Item contains a tab (only meaningful in popup menus) */
871 /* get text size before the tab */
872 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
873 DT_SINGLELINE
|DT_CALCRECT
);
874 txtwidth
= rc
.right
- rc
.left
;
875 p
+= 1; /* advance past the Tab */
876 /* get text size after the tab */
877 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
878 DT_SINGLELINE
|DT_CALCRECT
);
879 lpitem
->dxTab
+= txtwidth
;
880 txtheight
= max( txtheight
, tmpheight
);
881 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
882 tmprc
.right
- tmprc
.left
; /* space for the short cut */
884 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
885 DT_SINGLELINE
|DT_CALCRECT
);
886 txtwidth
= rc
.right
- rc
.left
;
887 lpitem
->dxTab
+= txtwidth
;
889 lpitem
->Rect
.right
+= 2 + txtwidth
;
890 itemheight
= max( itemheight
,
891 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
893 if (hfontOld
) SelectObject (hdc
, hfontOld
);
894 } else if( menuBar
) {
895 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
897 lpitem
->Rect
.bottom
+= itemheight
;
898 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
901 /***********************************************************************
902 * MenuPopupMenuCalcSize
904 * Calculate the size of a popup menu.
906 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
908 ROSMENUITEMINFO lpitem
;
911 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
913 MenuInfo
->Width
= MenuInfo
->Height
= 0;
914 if (MenuInfo
->MenuItemCount
== 0)
916 MenuSetRosMenuInfo(MenuInfo
);
921 SelectObject( hdc
, hMenuFont
);
926 MenuInfo
->maxBmpSize
.cx
= 0;
927 MenuInfo
->maxBmpSize
.cy
= 0;
929 MenuInitRosMenuItemInfo(&lpitem
);
930 while (start
< MenuInfo
->MenuItemCount
)
935 maxTab
= maxTabWidth
= 0;
937 /* Parse items until column break or end of menu */
938 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
940 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
942 MenuCleanupRosMenuItemInfo(&lpitem
);
943 MenuSetRosMenuInfo(MenuInfo
);
947 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
949 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
950 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
952 MenuCleanupRosMenuItemInfo(&lpitem
);
953 MenuSetRosMenuInfo(MenuInfo
);
956 // Not sure here,, The patch from wine removes this.
957 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
961 maxX
= max(maxX
, lpitem
.Rect
.right
);
962 orgY
= lpitem
.Rect
.bottom
;
963 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
965 maxTab
= max( maxTab
, lpitem
.dxTab
);
966 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
970 /* Finish the column (set all items to the largest width found) */
971 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
974 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
976 lpitem
.Rect
.right
= maxX
;
977 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
979 lpitem
.dxTab
= maxTab
;
981 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
985 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
988 MenuInfo
->Width
= maxX
;
990 /* space for 3d border */
991 MenuInfo
->Height
+= 2;
992 MenuInfo
->Width
+= 2;
994 MenuCleanupRosMenuItemInfo(&lpitem
);
995 MenuSetRosMenuInfo(MenuInfo
);
999 /***********************************************************************
1000 * MenuMenuBarCalcSize
1002 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1003 * height is off by 1 pixel which causes lengthy window relocations when
1004 * active document window is maximized/restored.
1006 * Calculate the size of the menu bar.
1008 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1009 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1011 ROSMENUITEMINFO ItemInfo
;
1012 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1014 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1015 if (MenuInfo
->MenuItemCount
== 0) return;
1016 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1017 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1018 MenuInfo
->Height
= 0;
1019 maxY
= lprect
->top
+ 1;
1023 MenuInfo
->maxBmpSize
.cx
= 0;
1024 MenuInfo
->maxBmpSize
.cy
= 0;
1026 MenuInitRosMenuItemInfo(&ItemInfo
);
1027 while (start
< MenuInfo
->MenuItemCount
)
1029 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1031 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1034 orgX
= lprect
->left
;
1037 /* Parse items until line break or end of menu */
1038 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1040 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1042 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1044 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1045 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1046 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1048 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1052 if (ItemInfo
.Rect
.right
> lprect
->right
)
1054 if (i
!= start
) break;
1055 else ItemInfo
.Rect
.right
= lprect
->right
;
1057 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1058 orgX
= ItemInfo
.Rect
.right
;
1059 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1061 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1063 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1069 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1070 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1072 /* Finish the line (set all items to the largest height found) */
1075 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1077 ItemInfo
.Rect
.bottom
= maxY
;
1078 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1083 start
= i
; /* This works! */
1087 lprect
->bottom
= maxY
;
1088 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1089 MenuSetRosMenuInfo(MenuInfo
);
1093 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1094 /* the last item (if several lines, only move the last line) */
1095 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1097 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1100 orgY
= ItemInfo
.Rect
.top
;
1101 orgX
= lprect
->right
;
1102 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1108 if (ItemInfo
.Rect
.top
!= orgY
)
1110 break; /* Other line */
1112 if (orgX
<= ItemInfo
.Rect
.right
)
1114 break; /* Too far right already */
1116 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1117 ItemInfo
.Rect
.right
= orgX
;
1118 orgX
= ItemInfo
.Rect
.left
;
1119 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1120 if (helpPos
+ 1 <= i
&&
1121 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1123 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1129 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1132 /***********************************************************************
1135 * Draw a single menu item.
1137 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1138 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1142 BOOL flat_menu
= FALSE
;
1144 PWND Wnd
= ValidateHwnd(hWnd
);
1149 if (lpitem
->fType
& MF_SYSMENU
)
1151 if ( (Wnd
->style
& WS_MINIMIZE
))
1153 UserGetInsideRectNC(Wnd
, &rect
);
1154 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1155 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1160 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1161 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1165 if (lpitem
->fState
& MF_HILITE
)
1167 if(menuBar
&& !flat_menu
) {
1168 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1169 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1171 if (lpitem
->fState
& MF_GRAYED
)
1172 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1174 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1175 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1180 if (lpitem
->fState
& MF_GRAYED
)
1181 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1183 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1184 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1187 rect
= lpitem
->Rect
;
1189 if (lpitem
->fType
& MF_OWNERDRAW
)
1192 ** Experimentation under Windows reveals that an owner-drawn
1193 ** menu is given the rectangle which includes the space it requested
1194 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1195 ** and a popup-menu arrow. This is the value of lpitem->rect.
1196 ** Windows will leave all drawing to the application except for
1197 ** the popup-menu arrow. Windows always draws that itself, after
1198 ** the menu owner has finished drawing.
1202 dis
.CtlType
= ODT_MENU
;
1204 dis
.itemID
= lpitem
->wID
;
1205 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1207 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1208 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1209 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1210 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1211 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1214 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1215 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1216 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1217 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1219 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1220 /* Draw the popup-menu arrow */
1221 if (lpitem
->fType
& MF_POPUP
)
1224 CopyRect(&rectTemp
, &rect
);
1225 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1226 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1231 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1233 if (lpitem
->fState
& MF_HILITE
)
1237 InflateRect (&rect
, -1, -1);
1238 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1239 InflateRect (&rect
, 1, 1);
1240 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1245 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1247 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1251 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1253 SetBkMode( hdc
, TRANSPARENT
);
1255 /* vertical separator */
1256 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1263 rc
.bottom
= Height
- 3;
1266 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1267 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1268 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1269 LineTo( hdc
, rc
.left
, rc
.bottom
);
1270 SelectObject( hdc
, oldPen
);
1273 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1276 /* horizontal separator */
1277 if (lpitem
->fType
& MF_SEPARATOR
)
1284 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1287 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1288 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1289 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1290 LineTo( hdc
, rc
.right
, rc
.top
);
1291 SelectObject( hdc
, oldPen
);
1294 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1299 /* helper lines for debugging */
1300 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1301 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1302 SelectObject(hdc
, GetStockObject(DC_PEN
));
1303 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1304 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1305 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1311 INT y
= rect
.top
+ rect
.bottom
;
1313 int checked
= FALSE
;
1314 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1315 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1316 /* Draw the check mark
1319 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1321 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1322 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1323 lpitem
->hbmpUnchecked
;
1324 if (bm
) /* we have a custom bitmap */
1326 HDC hdcMem
= CreateCompatibleDC( hdc
);
1328 SelectObject( hdcMem
, bm
);
1329 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1330 check_bitmap_width
, check_bitmap_height
,
1331 hdcMem
, 0, 0, SRCCOPY
);
1335 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1338 CopyRect(&r
, &rect
);
1339 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1340 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1341 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1342 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1346 if ( lpitem
->hbmpItem
)
1349 CopyRect(&bmpRect
, &rect
);
1350 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1351 bmpRect
.left
+= check_bitmap_width
+ 2;
1352 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1354 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1355 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1358 /* Draw the popup-menu arrow */
1359 if (lpitem
->fType
& MF_POPUP
)
1362 CopyRect(&rectTemp
, &rect
);
1363 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1364 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1367 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1368 rect
.left
+= check_bitmap_width
;
1369 rect
.right
-= check_bitmap_width
;
1371 else if( lpitem
->hbmpItem
)
1372 { /* Draw the bitmap */
1373 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1376 /* process text if present */
1382 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1383 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1385 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1386 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1388 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1390 if ( lpitem
->fState
& MFS_DEFAULT
)
1392 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1396 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1397 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1400 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1403 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1404 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1408 if(lpitem
->fState
& MF_GRAYED
)
1410 if (!(lpitem
->fState
& MF_HILITE
) )
1412 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1413 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1414 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1415 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1417 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1420 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1422 /* paint the shortcut text */
1423 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1425 if (L
'\t' == Text
[i
])
1427 rect
.left
= lpitem
->dxTab
;
1428 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1432 rect
.right
= lpitem
->dxTab
;
1433 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1436 if (lpitem
->fState
& MF_GRAYED
)
1438 if (!(lpitem
->fState
& MF_HILITE
) )
1440 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1441 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1442 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1443 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1445 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1447 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1451 SelectObject (hdc
, hfontOld
);
1455 /***********************************************************************
1458 * Paint a popup menu.
1460 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1462 HBRUSH hPrevBrush
= 0;
1465 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1467 GetClientRect( hwnd
, &rect
);
1469 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1470 && (SelectObject( hdc
, hMenuFont
)))
1474 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1476 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1479 BOOL flat_menu
= FALSE
;
1480 ROSMENUINFO MenuInfo
;
1481 ROSMENUITEMINFO ItemInfo
;
1483 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1485 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1487 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1489 /* draw menu items */
1490 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1494 MenuInitRosMenuItemInfo(&ItemInfo
);
1496 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1498 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1500 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1501 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1505 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1509 SelectObject( hdc
, hPrevBrush
);
1514 /***********************************************************************
1517 * Paint a menu bar. Returns the height of the menu bar.
1518 * called from [windows/nonclient.c]
1520 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1525 HMENU hMenu
= GetMenu(hwnd
);
1527 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1529 return GetSystemMetrics(SM_CYMENU
);
1534 hfontOld
= SelectObject(hDC
, hMenuFont
);
1536 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1538 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1540 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1541 return lppop
.Height
;
1544 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1547 /***********************************************************************
1550 * Display a popup menu.
1552 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1553 INT x
, INT y
, INT xanchor
, INT yanchor
)
1555 ROSMENUINFO MenuInfo
;
1556 ROSMENUITEMINFO ItemInfo
;
1562 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1563 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1565 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1566 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1568 MenuInitRosMenuItemInfo(&ItemInfo
);
1569 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1571 ItemInfo
.fMask
|= MIIM_STATE
;
1572 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1573 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1575 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1576 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1579 /* store the owner for DrawItem */
1580 MenuInfo
.WndOwner
= hwndOwner
;
1581 MenuSetRosMenuInfo(&MenuInfo
);
1583 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1585 /* adjust popup menu pos so that it fits within the desktop */
1587 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1588 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1590 /* FIXME: should use item rect */
1593 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1594 info
.cbSize
= sizeof(info
);
1595 GetMonitorInfoW( monitor
, &info
);
1597 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1598 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1600 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1601 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1603 if( x
+ width
> info
.rcMonitor
.right
)
1605 if( xanchor
&& x
>= width
- xanchor
)
1606 x
-= width
- xanchor
;
1608 if( x
+ width
> info
.rcMonitor
.right
)
1609 x
= info
.rcMonitor
.right
- width
;
1611 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
1613 if( y
+ height
> info
.rcMonitor
.bottom
)
1615 if( yanchor
&& y
>= height
+ yanchor
)
1616 y
-= height
+ yanchor
;
1618 if( y
+ height
> info
.rcMonitor
.bottom
)
1619 y
= info
.rcMonitor
.bottom
- height
;
1621 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
1623 /* NOTE: In Windows, top menu popup is not owned. */
1624 MenuInfo
.Wnd
= CreateWindowExW( 0, WC_MENU
, NULL
,
1625 WS_POPUP
, x
, y
, width
, height
,
1626 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1627 (LPVOID
) MenuInfo
.Self
);
1628 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1630 top_popup
= MenuInfo
.Wnd
;
1631 top_popup_hmenu
= hmenu
;
1634 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1636 /* Display the window */
1638 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1639 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1640 UpdateWindow( MenuInfo
.Wnd
);
1645 /***********************************************************************
1648 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1649 BOOL sendMenuSelect
, HMENU topmenu
)
1651 ROSMENUITEMINFO ItemInfo
;
1652 ROSMENUINFO TopMenuInfo
;
1655 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1657 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1658 if (hmenu
->FocusedItem
== wIndex
) return;
1659 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1660 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1662 top_popup
= hmenu
->Wnd
;
1663 top_popup_hmenu
= hmenu
->Self
;
1666 SelectObject( hdc
, hMenuFont
);
1668 MenuInitRosMenuItemInfo(&ItemInfo
);
1670 /* Clear previous highlighted item */
1671 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1673 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1675 ItemInfo
.fMask
|= MIIM_STATE
;
1676 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1677 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1679 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1680 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1684 /* Highlight new item (if any) */
1685 hmenu
->FocusedItem
= wIndex
;
1686 MenuSetRosMenuInfo(hmenu
);
1687 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1689 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1691 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1693 ItemInfo
.fMask
|= MIIM_STATE
;
1694 ItemInfo
.fState
|= MF_HILITE
;
1695 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1696 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1697 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1702 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1703 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1704 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1705 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1709 else if (sendMenuSelect
) {
1712 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1713 if (pos
!= NO_SELECTED_ITEM
)
1715 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1716 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1718 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1719 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1721 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1727 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1728 ReleaseDC(hmenu
->Wnd
, hdc
);
1731 /***********************************************************************
1734 * Moves currently selected item according to the Offset parameter.
1735 * If there is no selection then it should select the last item if
1736 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1738 static void FASTCALL
1739 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1742 ROSMENUITEMINFO ItemInfo
;
1745 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1747 /* Prevent looping */
1748 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1750 else if (Offset
< -1)
1752 else if (Offset
> 1)
1755 MenuInitRosMenuItemInfo(&ItemInfo
);
1757 OrigPos
= MenuInfo
->FocusedItem
;
1758 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1765 i
= MenuInfo
->FocusedItem
;
1772 /* Clip and wrap around */
1775 i
= MenuInfo
->MenuItemCount
- 1;
1777 else if (i
>= MenuInfo
->MenuItemCount
)
1781 /* If this is a good candidate; */
1782 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1783 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1785 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1786 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1789 } while (i
!= OrigPos
);
1792 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1795 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1797 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1803 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1804 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1808 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1809 return MA_NOACTIVATE
;
1814 BeginPaint(Wnd
, &ps
);
1815 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1820 case WM_PRINTCLIENT
:
1822 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1823 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1831 /* zero out global pointer in case resident popup window was destroyed. */
1832 if (Wnd
== top_popup
)
1835 top_popup_hmenu
= NULL
;
1842 if (0 == GetWindowLongPtrA(Wnd
, 0))
1844 OutputDebugStringA("no menu to display\n");
1849 SetWindowLongPtrA(Wnd
, 0, 0);
1853 case MM_SETMENUHANDLE
:
1854 SetWindowLongPtrA(Wnd
, 0, wParam
);
1857 case MM_GETMENUHANDLE
:
1859 return GetWindowLongPtrA(Wnd
, 0);
1862 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1868 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1870 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1876 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1877 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1881 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1882 return MA_NOACTIVATE
;
1887 BeginPaint(Wnd
, &ps
);
1888 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1893 case WM_PRINTCLIENT
:
1895 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1896 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1904 /* zero out global pointer in case resident popup window was destroyed. */
1905 if (Wnd
== top_popup
)
1908 top_popup_hmenu
= NULL
;
1915 if (0 == GetWindowLongPtrW(Wnd
, 0))
1917 OutputDebugStringA("no menu to display\n");
1922 SetWindowLongPtrW(Wnd
, 0, 0);
1926 case MM_SETMENUHANDLE
:
1927 SetWindowLongPtrW(Wnd
, 0, wParam
);
1930 case MM_GETMENUHANDLE
:
1932 return GetWindowLongPtrW(Wnd
, 0);
1935 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1941 /**********************************************************************
1942 * MENU_ParseResource
1944 * Parse a standard menu resource and add items to the menu.
1945 * Return a pointer to the end of the resource.
1947 * NOTE: flags is equivalent to the mtOption field
1949 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1958 flags
= GET_WORD(res
);
1960 /* remove MF_END flag before passing it to AppendMenu()! */
1961 end
= (flags
& MF_END
);
1962 if(end
) flags
^= MF_END
;
1964 res
+= sizeof(WORD
);
1965 if(!(flags
& MF_POPUP
))
1968 res
+= sizeof(WORD
);
1972 res
+= strlen(str
) + 1;
1974 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1975 if (flags
& MF_POPUP
)
1977 hSubMenu
= CreatePopupMenu();
1978 if(!hSubMenu
) return NULL
;
1979 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1982 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1984 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1986 else /* Not a popup */
1991 flags
= MF_SEPARATOR
;
1995 if (*(LPCWSTR
)str
== 0)
1996 flags
= MF_SEPARATOR
;
1999 if (flags
& MF_SEPARATOR
)
2001 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2002 flags
|= MF_GRAYED
| MF_DISABLED
;
2006 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2008 AppendMenuW(hMenu
, flags
, id
,
2009 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2016 /**********************************************************************
2017 * MENUEX_ParseResource
2019 * Parse an extended menu resource and add items to the menu.
2020 * Return a pointer to the end of the resource.
2022 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2028 mii
.cbSize
= sizeof(mii
);
2029 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
2030 mii
.fType
= GET_DWORD(res
);
2031 res
+= sizeof(DWORD
);
2032 mii
.fState
= GET_DWORD(res
);
2033 res
+= sizeof(DWORD
);
2034 mii
.wID
= GET_DWORD(res
);
2035 res
+= sizeof(DWORD
);
2036 resinfo
= GET_WORD(res
);
2037 res
+= sizeof(WORD
);
2038 /* Align the text on a word boundary. */
2039 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2040 mii
.dwTypeData
= (LPWSTR
) res
;
2041 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2042 /* Align the following fields on a dword boundary. */
2043 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2045 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2046 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2048 if (resinfo
& 1) { /* Pop-up? */
2049 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2050 res
+= sizeof(DWORD
);
2051 mii
.hSubMenu
= CreatePopupMenu();
2054 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2055 DestroyMenu(mii
.hSubMenu
);
2058 mii
.fMask
|= MIIM_SUBMENU
;
2059 mii
.fType
|= MF_POPUP
;
2060 mii
.wID
= (UINT
) mii
.hSubMenu
;
2062 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
2064 mii
.fType
|= MF_SEPARATOR
;
2066 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2067 } while (!(resinfo
& MF_END
));
2072 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2074 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2075 LRESULT Result
= (LRESULT
)hmenu
;
2076 MENUINFO menuinfo
= {0};
2077 MENUITEMINFOW info
= {0};
2079 // removing space for checkboxes from menu
2080 menuinfo
.cbSize
= sizeof(menuinfo
);
2081 menuinfo
.fMask
= MIM_STYLE
;
2082 GetMenuInfo(hmenu
, &menuinfo
);
2083 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2084 SetMenuInfo(hmenu
, &menuinfo
);
2086 // adding bitmaps to menu items
2087 info
.cbSize
= sizeof(info
);
2088 info
.fMask
|= MIIM_BITMAP
;
2089 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2090 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2091 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2092 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2093 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2094 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2095 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2096 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2098 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2105 NONCLIENTMETRICSW ncm
;
2107 /* get the menu font */
2108 if(!hMenuFont
|| !hMenuFontBold
)
2110 ncm
.cbSize
= sizeof(ncm
);
2111 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2113 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2117 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2118 if(hMenuFont
== NULL
)
2120 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2124 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2125 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2126 if(hMenuFontBold
== NULL
)
2128 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2129 DeleteObject(hMenuFont
);
2143 DeleteObject(hMenuFont
);
2149 DeleteObject(hMenuFontBold
);
2150 hMenuFontBold
= NULL
;
2154 /***********************************************************************
2155 * DrawMenuBarTemp (USER32.@)
2159 * called by W98SE desk.cpl Control Panel Applet
2161 * Not 100% sure about the param names, but close.
2166 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2168 ROSMENUINFO MenuInfo
;
2169 ROSMENUITEMINFO ItemInfo
;
2171 HFONT FontOld
= NULL
;
2172 BOOL flat_menu
= FALSE
;
2174 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2178 Menu
= GetMenu(Wnd
);
2186 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2188 return GetSystemMetrics(SM_CYMENU
);
2191 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2193 FontOld
= SelectObject(DC
, Font
);
2195 if (0 == MenuInfo
.Height
)
2197 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2200 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2202 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2204 SelectObject(DC
, GetStockObject(DC_PEN
));
2205 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2206 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2207 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2209 if (0 == MenuInfo
.MenuItemCount
)
2211 SelectObject(DC
, FontOld
);
2212 return GetSystemMetrics(SM_CYMENU
);
2215 MenuInitRosMenuItemInfo(&ItemInfo
);
2216 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2218 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2220 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2221 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2224 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2226 SelectObject(DC
, FontOld
);
2228 return MenuInfo
.Height
;
2231 /***********************************************************************
2234 * Display the sub-menu of the selected item of this menu.
2235 * Return the handle of the submenu, or menu if no submenu to display.
2237 static HMENU FASTCALL
2238 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2240 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2242 ROSMENUITEMINFO ItemInfo
;
2243 ROSMENUINFO SubMenuInfo
;
2247 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2249 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2251 return MenuInfo
->Self
;
2254 MenuInitRosMenuItemInfo(&ItemInfo
);
2255 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2257 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2258 return MenuInfo
->Self
;
2260 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2262 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2263 return MenuInfo
->Self
;
2266 /* message must be sent before using item,
2267 because nearly everything may be changed by the application ! */
2269 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2270 if (0 == (Flags
& TPM_NONOTIFY
))
2272 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2273 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2276 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2278 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2279 return MenuInfo
->Self
;
2281 Rect
= ItemInfo
.Rect
;
2283 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2284 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2286 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2288 Dc
= GetDC(MenuInfo
->Wnd
);
2292 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2295 SelectObject(Dc
, hMenuFont
);
2296 ItemInfo
.fMask
|= MIIM_STATE
;
2297 ItemInfo
.fState
|= MF_HILITE
;
2298 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2299 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2300 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2301 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2304 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2305 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2307 ItemInfo
.Rect
= Rect
;
2310 ItemInfo
.fMask
|= MIIM_STATE
;
2311 ItemInfo
.fState
|= MF_MOUSESELECT
;
2312 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2314 if (IS_SYSTEM_MENU(MenuInfo
))
2316 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2317 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2319 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2320 Rect
.top
= Rect
.bottom
;
2321 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2322 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2326 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2327 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2329 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2330 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2331 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2332 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2333 - GetSystemMetrics(SM_CYBORDER
);
2337 Rect
.left
+= ItemInfo
.Rect
.left
;
2338 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2339 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2340 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2344 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2345 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2346 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2348 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2351 Ret
= ItemInfo
.hSubMenu
;
2352 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2357 /**********************************************************************
2360 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2362 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2364 void MENU_EndMenu( HWND hwnd
)
2366 ROSMENUINFO MenuInfo
;
2368 if (top_popup_hmenu
)
2369 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2370 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2373 /***********************************************************************
2376 * Hide the sub-popup menus of this menu.
2378 static void FASTCALL
2379 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2380 BOOL SendMenuSelect
, UINT wFlags
)
2382 ROSMENUINFO SubMenuInfo
;
2383 ROSMENUITEMINFO ItemInfo
;
2385 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2387 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2389 MenuInitRosMenuItemInfo(&ItemInfo
);
2390 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2391 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2392 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2393 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2395 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2398 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2399 ItemInfo
.fMask
|= MIIM_STATE
;
2400 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2401 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2403 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2404 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2405 DestroyWindow(SubMenuInfo
.Wnd
);
2406 SubMenuInfo
.Wnd
= NULL
;
2407 MenuSetRosMenuInfo(&SubMenuInfo
);
2409 if (!(wFlags
& TPM_NONOTIFY
))
2410 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2411 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2416 /***********************************************************************
2417 * MenuSwitchTracking
2419 * Helper function for menu navigation routines.
2421 static void FASTCALL
2422 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2424 ROSMENUINFO TopMenuInfo
;
2426 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2428 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2429 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2430 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2432 /* both are top level menus (system and menu-bar) */
2433 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2434 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2435 Mt
->TopMenu
= PtMenuInfo
->Self
;
2439 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2442 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2445 /***********************************************************************
2446 * MenuExecFocusedItem
2448 * Execute a menu item (for instance when user pressed Enter).
2449 * Return the wID of the executed item. Otherwise, -1 indicating
2450 * that no menu item was executed, -2 if a popup is shown;
2451 * Have to receive the flags for the TrackPopupMenu options to avoid
2452 * sending unwanted message.
2456 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2458 ROSMENUITEMINFO ItemInfo
;
2461 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2463 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2468 MenuInitRosMenuItemInfo(&ItemInfo
);
2469 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2471 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2475 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2477 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2479 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2480 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2482 /* If TPM_RETURNCMD is set you return the id, but
2483 do not send a message to the owner */
2484 if (0 == (Flags
& TPM_RETURNCMD
))
2486 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2488 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2489 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2493 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2494 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2495 MenuInfo
->FocusedItem
,
2496 (LPARAM
)MenuInfo
->Self
);
2498 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2502 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2508 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2515 /***********************************************************************
2518 * Return TRUE if we can go on with menu tracking.
2520 static BOOL FASTCALL
2521 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2524 ROSMENUINFO MenuInfo
;
2525 ROSMENUITEMINFO Item
;
2527 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2531 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2535 if (IS_SYSTEM_MENU(&MenuInfo
))
2541 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2543 MenuInitRosMenuItemInfo(&Item
);
2544 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2546 MenuCleanupRosMenuItemInfo(&Item
);
2550 if (!(Item
.fType
& MF_SEPARATOR
) &&
2551 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2553 if (MenuInfo
.FocusedItem
!= Index
)
2555 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2558 /* If the popup menu is not already "popped" */
2559 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2561 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2565 MenuCleanupRosMenuItemInfo(&Item
);
2570 /* else the click was on the menu bar, finish the tracking */
2575 /***********************************************************************
2578 * Return the value of MenuExecFocusedItem if
2579 * the selected item was not a popup. Else open the popup.
2580 * A -1 return value indicates that we go on with menu tracking.
2584 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2587 ROSMENUINFO MenuInfo
;
2588 ROSMENUITEMINFO ItemInfo
;
2590 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2595 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2600 if (! IS_SYSTEM_MENU(&MenuInfo
))
2602 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2604 MenuInitRosMenuItemInfo(&ItemInfo
);
2605 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2606 MenuInfo
.FocusedItem
== Id
)
2608 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2610 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2611 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2612 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2614 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2616 /* If we are dealing with the top-level menu */
2617 /* and this is a click on an already "popped" item: */
2618 /* Stop the menu tracking and close the opened submenus */
2619 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2621 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2625 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2626 MenuInfo
.TimeToHide
= TRUE
;
2627 MenuSetRosMenuInfo(&MenuInfo
);
2633 /***********************************************************************
2636 * Walks menu chain trying to find a menu pt maps to.
2638 static HMENU FASTCALL
2639 MenuPtMenu(HMENU Menu
, POINT Pt
)
2641 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2642 ROSMENUINFO MenuInfo
;
2643 ROSMENUITEMINFO ItemInfo
;
2647 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2652 /* try subpopup first (if any) */
2653 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2655 MenuInitRosMenuItemInfo(&ItemInfo
);
2656 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2657 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2658 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2660 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2663 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2667 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2670 /* check the current window (avoiding WM_HITTEST) */
2671 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2672 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2674 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2679 else if (HTSYSMENU
== Ht
)
2681 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2683 else if (HTMENU
== Ht
)
2685 Ret
= GetMenu(MenuInfo
.Wnd
);
2691 /***********************************************************************
2694 * Return TRUE if we can go on with menu tracking.
2696 static BOOL FASTCALL
2697 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2700 ROSMENUINFO MenuInfo
;
2701 ROSMENUITEMINFO ItemInfo
;
2705 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2709 if (IS_SYSTEM_MENU(&MenuInfo
))
2715 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2720 Index
= NO_SELECTED_ITEM
;
2723 if (NO_SELECTED_ITEM
== Index
)
2725 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2726 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2728 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2732 else if (MenuInfo
.FocusedItem
!= Index
)
2734 MenuInitRosMenuItemInfo(&ItemInfo
);
2735 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2736 !(ItemInfo
.fType
& MF_SEPARATOR
))
2738 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2739 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2740 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2742 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2748 /***********************************************************************
2751 * Return the handle of the selected sub-popup menu (if any).
2753 static HMENU FASTCALL
2754 MenuGetSubPopup(HMENU Menu
)
2756 ROSMENUINFO MenuInfo
;
2757 ROSMENUITEMINFO ItemInfo
;
2759 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2760 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2765 MenuInitRosMenuItemInfo(&ItemInfo
);
2766 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2768 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2771 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2773 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2774 return ItemInfo
.hSubMenu
;
2777 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2781 /***********************************************************************
2784 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2786 static LRESULT FASTCALL
2787 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2789 ROSMENUINFO TopMenuInfo
;
2790 ROSMENUINFO MenuInfo
;
2792 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2794 return (LRESULT
) FALSE
;
2797 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2798 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2800 MDINEXTMENU NextMenu
;
2805 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2806 NextMenu
.hmenuNext
= NULL
;
2807 NextMenu
.hwndNext
= NULL
;
2808 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2810 TRACE("%p [%p] -> %p [%p]\n",
2811 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2813 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2815 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2816 NewWnd
= Mt
->OwnerWnd
;
2817 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2819 /* switch to the menu bar */
2821 if (0 != (Style
& WS_CHILD
)
2822 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2829 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2833 Id
= MenuInfo
.MenuItemCount
- 1;
2836 else if (0 != (Style
& WS_SYSMENU
))
2838 /* switch to the system menu */
2839 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2846 else /* application returned a new menu to switch to */
2848 NewMenu
= NextMenu
.hmenuNext
;
2849 NewWnd
= NextMenu
.hwndNext
;
2851 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2853 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2855 if (0 != (Style
& WS_SYSMENU
)
2856 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2858 /* get the real system menu */
2859 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2861 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2863 /* FIXME: Not sure what to do here;
2864 * perhaps try to track NewMenu as a popup? */
2866 WARN(" -- got confused.\n");
2876 if (NewMenu
!= Mt
->TopMenu
)
2878 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2880 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2882 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2886 if (NewWnd
!= Mt
->OwnerWnd
)
2888 Mt
->OwnerWnd
= NewWnd
;
2889 SetCapture(Mt
->OwnerWnd
);
2890 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2893 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2894 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2896 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2905 /***********************************************************************
2908 * The idea is not to show the popup if the next input message is
2909 * going to hide it anyway.
2911 static BOOL FASTCALL
2912 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2916 Msg
.hwnd
= Mt
->OwnerWnd
;
2918 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2919 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2924 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2925 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2927 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2928 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2929 if (WM_KEYDOWN
== Msg
.message
2930 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2932 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2939 /* failures go through this */
2940 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2945 /***********************************************************************
2948 * Handle a VK_ESCAPE key event in a menu.
2950 static BOOL FASTCALL
2951 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2953 BOOL EndMenu
= TRUE
;
2954 ROSMENUINFO MenuInfo
;
2955 HMENU MenuTmp
, MenuPrev
;
2957 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2959 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2960 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2962 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2964 /* close topmost popup */
2965 while (MenuTmp
!= Mt
->CurrentMenu
)
2968 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2971 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2973 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
2975 Mt
->CurrentMenu
= MenuPrev
;
2983 /***********************************************************************
2986 * Handle a VK_LEFT key event in a menu.
2988 static void FASTCALL
2989 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2991 ROSMENUINFO MenuInfo
;
2992 ROSMENUINFO TopMenuInfo
;
2993 ROSMENUINFO PrevMenuInfo
;
2994 HMENU MenuTmp
, MenuPrev
;
2997 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2999 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3004 /* Try to move 1 column left (if possible) */
3005 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3007 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3009 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3014 /* close topmost popup */
3015 while (MenuTmp
!= Mt
->CurrentMenu
)
3018 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3021 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3025 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3026 Mt
->CurrentMenu
= MenuPrev
;
3028 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3032 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3034 /* move menu bar selection if no more popups are left */
3036 if (! MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3038 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3041 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3043 /* A sublevel menu was displayed - display the next one
3044 * unless there is another displacement coming up */
3046 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3047 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3049 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3056 /***********************************************************************
3059 * Handle a VK_RIGHT key event in a menu.
3061 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3064 ROSMENUINFO MenuInfo
;
3065 ROSMENUINFO CurrentMenuInfo
;
3068 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3069 Mt
->CurrentMenu
, Mt
->TopMenu
);
3071 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3072 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3074 /* If already displaying a popup, try to display sub-popup */
3076 hmenutmp
= Mt
->CurrentMenu
;
3077 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3079 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3082 /* if subpopup was displayed then we are done */
3083 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3086 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3091 /* Check to see if there's another column */
3092 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3094 TRACE("Going to %d.\n", NextCol
);
3095 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3097 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3102 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3104 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3106 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3107 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3114 /* try to move to the next item */
3115 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3116 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3118 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3120 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3121 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3123 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3130 /***********************************************************************
3133 * Menu tracking code.
3135 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3136 HWND hwnd
, const RECT
*lprect
)
3139 ROSMENUINFO MenuInfo
;
3140 ROSMENUITEMINFO ItemInfo
;
3142 INT executedMenuId
= -1;
3144 BOOL enterIdleSent
= FALSE
;
3147 mt
.CurrentMenu
= hmenu
;
3153 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3154 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3155 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3159 WARN("Invalid menu handle %p\n", hmenu
);
3160 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3165 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3170 if (wFlags
& TPM_BUTTONDOWN
)
3172 /* Get the result in order to start the tracking or not */
3173 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3174 fEndMenu
= !fRemove
;
3177 SetCapture(mt
.OwnerWnd
);
3178 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, mt
.OwnerWnd
);
3180 FIXME("MenuTrackMenu 1\n");
3183 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, VALIDATE_TYPE_MENU
);
3184 if (!menu
) /* sometimes happens if I do a window manager close */
3187 /* we have to keep the message in the queue until it's
3188 * clear that menu loop is not over yet. */
3192 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3194 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3195 /* remove the message from the queue */
3196 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3202 HWND win
= MenuInfo
.Flags
& MF_POPUP
? MenuInfo
.Wnd
: NULL
;
3203 enterIdleSent
= TRUE
;
3204 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3208 //FIXME("MenuTrackMenu loop 1\n");
3211 /* check if EndMenu() tried to cancel us, by posting this message */
3212 if (msg
.message
== WM_CANCELMODE
)
3214 /* we are now out of the loop */
3217 /* remove the message from the queue */
3218 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3220 /* break out of internal loop, ala ESCAPE */
3224 TranslateMessage( &msg
);
3227 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3228 enterIdleSent
=FALSE
;
3231 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3234 * Use the mouse coordinates in lParam instead of those in the MSG
3235 * struct to properly handle synthetic messages. They are already
3236 * in screen coordinates.
3238 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3239 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3241 /* Find a menu for this mouse event */
3242 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3246 /* no WM_NC... messages in captured state */
3248 case WM_RBUTTONDBLCLK
:
3249 case WM_RBUTTONDOWN
:
3250 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3252 case WM_LBUTTONDBLCLK
:
3253 case WM_LBUTTONDOWN
:
3254 /* If the message belongs to the menu, removes it from the queue */
3255 /* Else, end menu tracking */
3256 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3257 fEndMenu
= !fRemove
;
3261 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3264 /* Check if a menu was selected by the mouse */
3267 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3268 TRACE("executedMenuId %d\n", executedMenuId
);
3270 /* End the loop if executedMenuId is an item ID */
3271 /* or if the job was done (executedMenuId = 0). */
3272 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3274 /* No menu was selected by the mouse */
3275 /* if the function was called by TrackPopupMenu, continue
3276 with the menu tracking. If not, stop it */
3278 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3283 /* the selected menu item must be changed every time */
3284 /* the mouse moves. */
3287 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3289 } /* switch(msg.message) - mouse */
3291 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3293 fRemove
= TRUE
; /* Keyboard messages are always removed */
3307 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3309 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
3310 NO_SELECTED_ITEM
, FALSE
, 0 );
3311 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3312 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3317 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3318 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3320 if (!(MenuInfo
.Flags
& MF_POPUP
))
3322 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3323 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3325 else /* otherwise try to move selection */
3326 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3327 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3332 MenuKeyLeft( &mt
, wFlags
);
3336 MenuKeyRight( &mt
, wFlags
);
3340 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3346 hi
.cbSize
= sizeof(HELPINFO
);
3347 hi
.iContextType
= HELPINFO_MENUITEM
;
3348 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3350 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
)
3354 MenuInitRosMenuItemInfo(&ItemInfo
);
3355 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3356 MenuInfo
.FocusedItem
,
3359 hi
.iCtrlId
= ItemInfo
.wID
;
3365 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3368 hi
.hItemHandle
= hmenu
;
3369 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3370 hi
.MousePos
= msg
.pt
;
3371 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3378 break; /* WM_KEYDOWN */
3385 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3386 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3388 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3389 fEndMenu
= (executedMenuId
!= -2);
3393 /* Hack to avoid control chars. */
3394 /* We will find a better way real soon... */
3395 if (msg
.wParam
< 32) break;
3397 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3398 LOWORD(msg
.wParam
), FALSE
);
3399 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3400 else if (pos
== (UINT
)-1) MessageBeep(0);
3403 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3405 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3406 fEndMenu
= (executedMenuId
!= -2);
3410 } /* switch(msg.message) - kbd */
3414 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3415 DispatchMessageW( &msg
);
3416 //FIXME("MenuTrackMenu loop 2\n");
3420 if (!fEndMenu
) fRemove
= TRUE
;
3422 /* finally remove message from the queue */
3424 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3425 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3426 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3427 //FIXME("MenuTrackMenu loop 3\n");
3429 FIXME("MenuTrackMenu 2\n");
3431 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3432 SetCapture(NULL
); /* release the capture */
3434 /* If dropdown is still painted and the close box is clicked on
3435 then the menu will be destroyed as part of the DispatchMessage above.
3436 This will then invalidate the menu handle in mt.hTopMenu. We should
3437 check for this first. */
3438 if( IsMenu( mt
.TopMenu
) )
3440 if (IsWindow(mt
.OwnerWnd
))
3442 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3444 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3446 if (MenuInfo
.Flags
& MF_POPUP
)
3448 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3449 DestroyWindow(MenuInfo
.Wnd
);
3450 MenuInfo
.Wnd
= NULL
;
3452 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3453 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3454 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3457 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3460 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3463 /* Reset the variable for hiding menu */
3464 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3466 MenuInfo
.TimeToHide
= FALSE
;
3467 MenuSetRosMenuInfo(&MenuInfo
);
3471 /* The return value is only used by TrackPopupMenu */
3472 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3473 if (executedMenuId
== -1) executedMenuId
= 0;
3474 return executedMenuId
;
3477 /***********************************************************************
3480 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3482 ROSMENUINFO MenuInfo
;
3484 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3488 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
3489 /* This makes the menus of applications built with Delphi work.
3490 * It also enables menus to be displayed in more than one window,
3491 * but there are some bugs left that need to be fixed in this case.
3493 if(MenuInfo
.Self
== hMenu
)
3495 MenuInfo
.Wnd
= hWnd
;
3496 MenuSetRosMenuInfo(&MenuInfo
);
3499 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3500 if (!(wFlags
& TPM_NONOTIFY
))
3501 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3503 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3505 if (!(wFlags
& TPM_NONOTIFY
))
3507 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3508 /* If an app changed/recreated menu bar entries in WM_INITMENU
3509 * menu sizes will be recalculated once the menu created/shown.
3512 if (!MenuInfo
.Height
)
3514 /* app changed/recreated menu bar entries in WM_INITMENU
3515 Recalculate menu sizes else clicks will not work */
3516 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3517 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3522 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
3524 MenuInfo
.Flags
& MF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
3528 /***********************************************************************
3531 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
3533 TRACE("hwnd=%p\n", hWnd
);
3535 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
3536 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
3539 top_popup_hmenu
= NULL
;
3543 /***********************************************************************
3544 * MenuTrackMouseMenuBar
3546 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3548 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3550 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3551 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3553 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3557 /* map point to parent client coordinates */
3558 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3559 if (Parent
!= GetDesktopWindow())
3561 ScreenToClient(Parent
, &pt
);
3564 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3565 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3566 MenuExitTracking(hWnd
, FALSE
);
3571 /***********************************************************************
3572 * MenuTrackKbdMenuBar
3574 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3576 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3578 UINT uItem
= NO_SELECTED_ITEM
;
3580 ROSMENUINFO MenuInfo
;
3581 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3583 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3585 /* find window that has a menu */
3587 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3588 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3589 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3591 /* check if we have to track a system menu */
3593 hTrackMenu
= GetMenu( hwnd
);
3594 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3596 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3597 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3599 wParam
|= HTSYSMENU
; /* prevent item lookup */
3602 if (!IsMenu( hTrackMenu
)) return;
3604 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3606 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3611 if( wChar
&& wChar
!= ' ' )
3613 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3614 if ( uItem
>= (UINT
)(-2) )
3616 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3617 /* schedule end of menu tracking */
3618 wFlags
|= TF_ENDMENU
;
3623 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3625 if (wParam
& HTSYSMENU
)
3627 /* prevent sysmenu activation for managed windows on Alt down/up */
3628 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3629 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3633 if( uItem
== NO_SELECTED_ITEM
)
3634 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3636 PostMessageW( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3640 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3641 MenuExitTracking( hwnd
, FALSE
);
3645 /**********************************************************************
3646 * TrackPopupMenuEx (USER32.@)
3648 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
3649 HWND Wnd
, LPTPMPARAMS Tpm
)
3652 ROSMENUINFO MenuInfo
;
3656 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3660 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
3661 if (IsWindow(MenuInfo
.Wnd
))
3663 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
3667 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
3669 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3670 if (!(Flags
& TPM_NONOTIFY
))
3671 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
3673 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
3674 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
3675 Tpm
? &Tpm
->rcExclude
: NULL
);
3676 MenuExitTracking(Wnd
, TRUE
);
3680 /**********************************************************************
3681 * TrackPopupMenu (USER32.@)
3683 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
3684 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
3686 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
3691 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3692 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3694 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3696 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3697 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3698 * MFT_STRING is replaced by MIIM_STRING.
3699 * (So, I guess we should use MIIM_STRING only for strings?)
3701 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3703 * Based on wine, SetMenuItemInfo_common:
3704 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3705 * it will result in a error.
3706 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3707 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3714 LPMENUITEMINFOW mii
,
3721 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3723 if(Flags
& MF_BITMAP
)
3725 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3726 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3728 if (Flags
& MF_HELP
)
3730 /* increase ident */
3731 mii
->fType
|= MF_HELP
;
3734 else if(Flags
& MF_OWNERDRAW
)
3736 mii
->fType
|= MFT_OWNERDRAW
;
3737 mii
->fMask
|= MIIM_DATA
;
3738 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
3740 else if (Flags
& MF_SEPARATOR
)
3742 mii
->fType
|= MFT_SEPARATOR
;
3743 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3744 Flags
|= MF_GRAYED
|MF_DISABLED
;
3746 else /* Default action MF_STRING. */
3748 /* Item beginning with a backspace is a help item */
3749 if (NewItem
!= NULL
)
3753 if (*NewItem
== '\b')
3755 mii
->fType
|= MF_HELP
;
3761 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3762 if (*NewItemA
== '\b')
3764 mii
->fType
|= MF_HELP
;
3766 NewItem
= (LPCWSTR
) NewItemA
;
3770 if (Flags
& MF_HELP
)
3771 mii
->fType
|= MF_HELP
;
3772 mii
->fMask
|= MIIM_STRING
;
3773 mii
->fType
|= MFT_STRING
; /* Zero */
3774 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3776 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3778 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3782 mii
->fType
|= MFT_SEPARATOR
;
3783 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3784 Flags
|= MF_GRAYED
|MF_DISABLED
;
3788 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3790 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3793 if(Flags
& MF_MENUBREAK
)
3795 mii
->fType
|= MFT_MENUBREAK
;
3797 else if(Flags
& MF_MENUBARBREAK
)
3799 mii
->fType
|= MFT_MENUBARBREAK
;
3802 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3804 if (Flags
& MF_GRAYED
)
3805 mii
->fState
|= MF_GRAYED
;
3807 if (Flags
& MF_DISABLED
)
3808 mii
->fState
|= MF_DISABLED
;
3810 mii
->fMask
|= MIIM_STATE
;
3812 else if (Flags
& MF_HILITE
)
3814 mii
->fState
|= MF_HILITE
;
3815 mii
->fMask
|= MIIM_STATE
;
3817 else /* default state */
3819 mii
->fState
|= MFS_ENABLED
;
3820 mii
->fMask
|= MIIM_STATE
;
3823 if(Flags
& MF_POPUP
)
3825 mii
->fType
|= MF_POPUP
;
3826 mii
->fMask
|= MIIM_SUBMENU
;
3827 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3831 mii
->fMask
|= MIIM_ID
;
3832 mii
->wID
= (UINT
)IDNewItem
;
3838 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3840 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3843 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3845 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3846 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3847 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3848 (LPCWSTR
)&Common
->MenuName
);
3850 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3854 /* FUNCTIONS *****************************************************************/
3857 MenuIsStringItem(ULONG TypeData)
3859 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3867 AppendMenuA(HMENU hMenu
,
3869 UINT_PTR uIDNewItem
,
3872 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3881 AppendMenuW(HMENU hMenu
,
3883 UINT_PTR uIDNewItem
,
3886 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3895 CheckMenuItem(HMENU hmenu
,
3899 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3904 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3907 PROSMENUITEMINFO Items
= NULL
;
3908 UINT cChecked
, cUnchecked
;
3912 if(idFirst
> idLast
)
3915 ItemCount
= GetMenuItemCount(hMenu
);
3917 //mi.cbSize = sizeof(ROSMENUINFO);
3918 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3921 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3923 ERR("MenuGetAllRosMenuItemInfo failed\n");
3927 cChecked
= cUnchecked
= 0;
3929 for (i
= 0 ; i
< ItemCount
; i
++)
3932 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3933 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3935 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3937 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3940 if (uFlags
& MF_BYPOSITION
)
3942 if (i
< idFirst
|| i
> idLast
)
3957 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3960 if (Items
[i
].wID
== idCheck
)
3974 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
3977 Items
[i
].fType
|= MFT_RADIOCHECK
;
3978 Items
[i
].fState
|= MFS_CHECKED
;
3982 Items
[i
].fState
&= ~MFS_CHECKED
;
3985 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
3987 ERR("MenuSetRosMenuItemInfo failed\n");
3992 HeapFree(GetProcessHeap(), 0, Items
);
3994 *pChecked
+= cChecked
;
3995 *pUnchecked
+= cUnchecked
;
3997 if (cChecked
|| cUnchecked
)
4007 CheckMenuRadioItem(HMENU hmenu
,
4014 UINT cUnchecked
= 0;
4015 UINT cMenuChanged
= 0;
4017 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4020 if (cMenuChanged
> 1)
4027 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4030 return (cChecked
!= 0);
4041 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4049 CreatePopupMenu(VOID
)
4052 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4060 DrawMenuBar(HWND hWnd
)
4062 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4063 ROSMENUINFO MenuInfo
;
4065 hMenu
= GetMenu(hWnd
);
4068 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4069 MenuInfo
.Height
= 0; // make sure to recalc size
4070 MenuSetRosMenuInfo(&MenuInfo
);
4072 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4073 SWP_NOZORDER
| SWP_FRAMECHANGED
);
4081 EnableMenuItem(HMENU hMenu
,
4085 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4095 guii
.cbSize
= sizeof(GUITHREADINFO
);
4096 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4100 guii
.hwndMenuOwner
!= top_popup
)
4102 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4106 /* if we are in the menu code, and it is active */
4107 if (!fEndMenu
&& top_popup
)
4109 /* terminate the menu handling code */
4112 /* needs to be posted to wakeup the internal menu handler */
4113 /* which will now terminate the menu, in the event that */
4114 /* the main window was minimized, or lost focus, so we */
4115 /* don't end up with an orphaned menu */
4116 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4121 // So this one maybe one day it will be a callback!
4122 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4125 ROSMENUINFO MenuInfo
;
4126 ROSMENUITEMINFO mii
;
4127 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4130 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4133 if (!NtUserMenuItemInfo(hMenu
, wItemID
, wHilite
, &mii
, FALSE
)) return FALSE
;
4134 if (!NtUserMenuInfo(hMenu
, &MenuInfo
, FALSE
)) return FALSE
;
4135 if (MenuInfo
.FocusedItem
== wItemID
) return TRUE
;
4136 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4137 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4147 PWND Wnd
= ValidateHwnd(hWnd
);
4152 return UlongToHandle(Wnd
->IDMenu
);
4160 GetMenuCheckMarkDimensions(VOID
)
4162 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4163 GetSystemMetrics(SM_CYMENUCHECK
)));
4171 GetMenuDefaultItem(HMENU hMenu
,
4175 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4183 GetMenuInfo(HMENU hmenu
,
4189 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4192 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4193 mi
.cbSize
= sizeof(MENUINFO
);
4194 mi
.fMask
= lpcmi
->fMask
;
4196 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4198 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4207 GetMenuItemCount(HMENU Menu
)
4209 ROSMENUINFO MenuInfo
;
4211 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4219 GetMenuItemID(HMENU hMenu
,
4222 ROSMENUITEMINFO mii
;
4224 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4225 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4227 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4232 if (NULL
!= mii
.hSubMenu
)
4253 LPMENUITEMINFOA mii
)
4259 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4260 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4262 SetLastError(ERROR_INVALID_PARAMETER
);
4266 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4268 /* No text requested, just pass on */
4269 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4272 AnsiBuffer
= mii
->dwTypeData
;
4273 Count
= miiW
.cch
= mii
->cch
;
4274 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4275 miiW
.dwTypeData
= 0;
4279 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4280 miiW
.cch
* sizeof(WCHAR
));
4281 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4282 miiW
.dwTypeData
[0] = 0;
4285 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4287 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4291 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4293 if (!AnsiBuffer
|| !Count
)
4295 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4296 mii
->dwTypeData
= AnsiBuffer
;
4297 mii
->cch
= miiW
.cch
;
4301 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4305 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4309 if (Count
> miiW
.cch
)
4311 AnsiBuffer
[miiW
.cch
] = 0;
4313 mii
->cch
= mii
->cch
;
4321 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4322 mii
->dwTypeData
= AnsiBuffer
;
4336 LPMENUITEMINFOW mii
)
4342 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4343 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4345 SetLastError(ERROR_INVALID_PARAMETER
);
4349 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4351 /* No text requested, just pass on */
4352 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4355 String
= mii
->dwTypeData
;
4357 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4358 miiW
.dwTypeData
= 0;
4362 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4363 miiW
.cch
* sizeof(WCHAR
));
4364 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4365 miiW
.dwTypeData
[0] = 0;
4368 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4370 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4374 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4376 if (!String
|| !Count
)
4378 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4379 mii
->dwTypeData
= String
; // may not be zero.
4380 mii
->cch
= miiW
.cch
;
4384 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4386 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4389 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4390 mii
->dwTypeData
= String
;
4391 mii
->cch
= strlenW(String
);
4406 ROSMENUINFO MenuInfo
;
4407 ROSMENUITEMINFO mii
;
4408 memset( &mii
, 0, sizeof(mii
) );
4409 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4410 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4413 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4418 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4422 nSubItems
= MenuInfo
.MenuItemCount
;
4424 /* FIXME - ported from wine, does that work (0xff)? */
4425 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4426 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4428 return (UINT
)-1; /* Invalid submenu */
4431 /* FIXME - ported from wine, does that work? */
4432 return (mii
.fType
| mii
.fState
);
4452 memset( &mii
, 0, sizeof(mii
) );
4453 mii
.dwTypeData
= lpString
;
4454 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4455 mii
.fType
= MFT_STRING
;
4456 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4457 mii
.cch
= nMaxCount
;
4459 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4479 memset( &miiW
, 0, sizeof(miiW
) );
4480 miiW
.dwTypeData
= lpString
;
4481 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4482 miiW
.fType
= MFT_STRING
;
4483 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4484 miiW
.cch
= nMaxCount
;
4486 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4504 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4505 mi
.fMask
= MIIM_SUBMENU
;
4507 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4509 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4526 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4528 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4541 UINT_PTR uIDNewItem
,
4545 memset( &mii
, 0, sizeof(mii
) );
4546 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4547 mii
.fMask
= MIIM_FTYPE
;
4549 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4552 (LPCWSTR
) lpNewItem
,
4555 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4569 LPCMENUITEMINFOA lpmii
)
4572 UNICODE_STRING MenuText
;
4574 BOOL CleanHeap
= FALSE
;
4577 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4578 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4580 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4582 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4584 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4587 /* copy the text string */
4588 if (((mi
.fMask
& MIIM_STRING
) ||
4589 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4590 && mi
.dwTypeData
!= NULL
)
4592 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4593 if (!NT_SUCCESS (Status
))
4595 SetLastError (RtlNtStatusToDosError(Status
));
4598 mi
.dwTypeData
= MenuText
.Buffer
;
4599 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4602 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4604 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4619 LPCMENUITEMINFOW lpmii
)
4622 UNICODE_STRING MenuText
;
4625 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4626 if a bad user passes bad data, we crash his process instead of the
4629 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4630 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4632 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4634 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4636 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4639 /* copy the text string */
4640 if (((mi
.fMask
& MIIM_STRING
) ||
4641 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4642 && mi
.dwTypeData
!= NULL
)
4644 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4645 mi
.dwTypeData
= MenuText
.Buffer
;
4646 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4648 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4663 UINT_PTR uIDNewItem
,
4667 memset( &mii
, 0, sizeof(mii
) );
4668 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4669 mii
.fMask
= MIIM_FTYPE
;
4671 MenuSetItemData( &mii
,
4677 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4689 if (ValidateHandle(Menu
, VALIDATE_TYPE_MENU
)) return TRUE
;
4698 LoadMenuA(HINSTANCE hInstance
,
4701 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4702 if (Resource
== NULL
)
4706 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4714 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4716 return(LoadMenuIndirectW(lpMenuTemplate
));
4724 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4727 WORD version
, offset
;
4728 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4730 version
= GET_WORD(p
);
4735 case 0: /* standard format is version of 0 */
4736 offset
= GET_WORD(p
);
4737 p
+= sizeof(WORD
) + offset
;
4738 if (!(hMenu
= CreateMenu())) return 0;
4739 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4745 case 1: /* extended format is version of 1 */
4746 offset
= GET_WORD(p
);
4747 p
+= sizeof(WORD
) + offset
;
4748 if (!(hMenu
= CreateMenu())) return 0;
4749 if (!MENUEX_ParseResource(p
, hMenu
))
4751 DestroyMenu( hMenu
);
4756 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4766 LoadMenuW(HINSTANCE hInstance
,
4769 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4770 if (Resource
== NULL
)
4774 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4788 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4801 UINT_PTR uIDNewItem
,
4805 ROSMENUITEMINFO rmii
;
4807 memset( &mii
, 0, sizeof(mii
) );
4808 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4809 mii
.fMask
= MIIM_FTYPE
;
4811 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4815 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4817 MenuInitRosMenuItemInfo( &rmii
);
4819 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4821 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4822 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4824 MenuCleanupRosMenuItemInfo( &rmii
);
4826 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4829 (LPCWSTR
) lpNewItem
,
4832 return SetMenuItemInfoA( hMnu
,
4834 (BOOL
)(MF_BYPOSITION
& uFlags
),
4848 UINT_PTR uIDNewItem
,
4852 ROSMENUITEMINFO rmii
;
4854 memset ( &mii
, 0, sizeof(mii
) );
4855 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4856 mii
.fMask
= MIIM_FTYPE
;
4858 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4860 mi
.Height
= 0; // Force size recalculation.
4862 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4864 MenuInitRosMenuItemInfo( &rmii
);
4866 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4868 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4869 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4871 MenuCleanupRosMenuItemInfo( &rmii
);
4873 /* Init new data for this menu item */
4874 MenuSetItemData( &mii
,
4880 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4881 return SetMenuItemInfoW( hMnu
,
4883 (BOOL
)(MF_BYPOSITION
& uFlags
),
4895 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4911 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4913 SetLastError(ERROR_INVALID_PARAMETER
);
4917 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4918 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4931 HBITMAP hBitmapUnchecked
,
4932 HBITMAP hBitmapChecked
)
4934 ROSMENUITEMINFO uItem
;
4935 memset ( &uItem
, 0, sizeof(uItem
) );
4936 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4938 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4939 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4941 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4943 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4945 else /* Install new bitmaps */
4947 uItem
.hbmpChecked
= hBitmapChecked
;
4948 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4949 uItem
.fState
|= MF_USECHECKBITMAPS
;
4951 return NtUserMenuItemInfo(hMenu
, uPosition
,
4952 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4965 LPCMENUITEMINFOA lpmii
)
4967 MENUITEMINFOW MenuItemInfoW
;
4968 UNICODE_STRING UnicodeString
;
4970 ULONG Result
= FALSE
;
4972 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4974 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4976 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4977 MenuItemInfoW
.hbmpItem
= NULL
;
4980 * MIIM_STRING == good
4981 * MIIM_TYPE & MFT_STRING == good
4982 * MIIM_STRING & MFT_STRING == good
4983 * MIIM_STRING & MFT_OWNERSRAW == good
4985 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4986 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4987 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4988 && MenuItemInfoW
.dwTypeData
!= NULL
)
4990 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
4991 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
4992 (LPSTR
)MenuItemInfoW
.dwTypeData
);
4993 if (!NT_SUCCESS (Status
))
4995 SetLastError (RtlNtStatusToDosError(Status
));
4998 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
4999 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5003 UnicodeString
.Buffer
= NULL
;
5006 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5007 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5009 if (UnicodeString
.Buffer
!= NULL
)
5011 RtlFreeUnicodeString(&UnicodeString
);
5027 LPCMENUITEMINFOW lpmii
)
5029 MENUITEMINFOW MenuItemInfoW
;
5032 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5034 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5036 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5037 MenuItemInfoW
.hbmpItem
= NULL
;
5040 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5041 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5042 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5043 && MenuItemInfoW
.dwTypeData
!= NULL
)
5045 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5047 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5048 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5064 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5069 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5072 return NtUserSetSystemMenu(hwnd
, hMenu
);
5076 // Example for the Win32/User32 rewrite.
5077 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5091 return NtUserTrackPopupMenuEx( Menu
,
5096 NULL
); // LPTPMPARAMS is null
5105 GetMenuContextHelpId(HMENU hmenu
)
5108 mi
.cbSize
= sizeof(ROSMENUINFO
);
5109 mi
.fMask
= MIM_HELPID
;
5111 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5113 return mi
.dwContextHelpID
;
5134 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5137 Result
= (ULONG_PTR
)lResult
;
5142 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5162 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5165 Result
= (ULONG_PTR
)lResult
;
5170 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5181 LPCWSTR lpszNewItem
,
5186 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5187 for MF_DELETE. We should check the parameters for all others
5188 MF_* actions also (anybody got a doc on ChangeMenu?).
5191 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5194 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5197 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5200 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5203 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5204 flags
&~ MF_REMOVE
);
5206 default : /* MF_INSERT */
5207 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5224 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5225 for MF_DELETE. We should check the parameters for all others
5226 MF_* actions also (anybody got a doc on ChangeMenu?).
5229 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5232 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5235 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5238 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5241 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5242 flags
&~ MF_REMOVE
);
5244 default : /* MF_INSERT */
5245 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);