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)
531 if ( !ForceMenuChar
)
534 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
536 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
538 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
541 p
= strchrW (p
+ 2, '&');
543 while (p
!= NULL
&& p
[1] == '&');
544 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
549 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
550 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
551 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
552 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
557 /***********************************************************************
558 * MenuGetBitmapItemSize
560 * Get the size of a bitmap item.
562 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
565 HBITMAP bmp
= lpitem
->hbmpItem
;
567 size
->cx
= size
->cy
= 0;
569 /* check if there is a magic menu item associated with this item */
570 if (IS_MAGIC_BITMAP(bmp
))
572 switch((INT_PTR
) bmp
)
574 case (INT_PTR
)HBMMENU_CALLBACK
:
576 MEASUREITEMSTRUCT measItem
;
577 measItem
.CtlType
= ODT_MENU
;
579 measItem
.itemID
= lpitem
->wID
;
580 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
581 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
582 measItem
.itemData
= lpitem
->dwItemData
;
583 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
584 size
->cx
= measItem
.itemWidth
;
585 size
->cy
= measItem
.itemHeight
;
590 case (INT_PTR
) HBMMENU_SYSTEM
:
591 if (0 != lpitem
->dwItemData
)
593 bmp
= (HBITMAP
) lpitem
->dwItemData
;
597 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
598 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
599 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
600 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
601 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
602 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
603 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
604 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
605 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
606 /* FIXME: Why we need to subtract these magic values? */
607 /* to make them smaller than the menu bar? */
608 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
609 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
614 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
616 size
->cx
= bm
.bmWidth
;
617 size
->cy
= bm
.bmHeight
;
621 /***********************************************************************
624 * Draw a bitmap item.
626 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
627 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
633 int w
= rect
->right
- rect
->left
;
634 int h
= rect
->bottom
- rect
->top
;
637 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
640 /* Check if there is a magic menu item associated with this item */
641 if (IS_MAGIC_BITMAP(hbmToDraw
))
647 switch ((INT_PTR
)hbmToDraw
)
649 case (INT_PTR
)HBMMENU_SYSTEM
:
650 if (lpitem
->dwTypeData
)
652 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
653 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
657 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
659 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
660 /* only use right half of the bitmap */
661 bmp_xoffset
= bm
.bmWidth
/ 2;
662 bm
.bmWidth
-= bmp_xoffset
;
665 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
666 flags
= DFCS_CAPTIONRESTORE
;
668 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
670 flags
= DFCS_CAPTIONMIN
;
672 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
674 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
676 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
677 flags
= DFCS_CAPTIONCLOSE
;
679 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
680 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
682 case (INT_PTR
)HBMMENU_CALLBACK
:
684 DRAWITEMSTRUCT drawItem
;
686 drawItem
.CtlType
= ODT_MENU
;
688 drawItem
.itemID
= lpitem
->wID
;
689 drawItem
.itemAction
= odaction
;
690 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
691 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
692 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
693 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
694 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
695 drawItem
.hwndItem
= (HWND
)hmenu
;
697 drawItem
.rcItem
= *rect
;
698 drawItem
.itemData
= lpitem
->dwItemData
;
699 /* some applications make this assumption on the DC's origin */
700 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
701 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
702 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
703 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
708 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
709 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
710 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
711 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
712 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
715 InflateRect(&r
, -1, -1);
716 if (0 != (lpitem
->fState
& MF_HILITE
))
718 flags
|= DFCS_PUSHED
;
720 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
724 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
727 hdcMem
= CreateCompatibleDC( hdc
);
728 SelectObject( hdcMem
, bmp
);
730 /* handle fontsize > bitmap_height */
731 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
733 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
734 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
735 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
736 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
740 /***********************************************************************
743 * Calculate the size of the menu item and store it in lpitem->rect.
745 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
746 INT orgX
, INT orgY
, BOOL menuBar
)
749 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
752 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
754 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
756 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
758 if (lpitem
->fType
& MF_OWNERDRAW
)
760 MEASUREITEMSTRUCT mis
;
761 mis
.CtlType
= ODT_MENU
;
763 mis
.itemID
= lpitem
->wID
;
764 mis
.itemData
= lpitem
->dwItemData
;
765 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
767 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
768 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
769 * width of a menufont character to the width of an owner-drawn menu.
771 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
774 /* under at least win95 you seem to be given a standard
775 height for the menu and the height value is ignored */
776 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
778 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
780 TRACE("id=%04lx size=%dx%d\n",
781 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
785 if (lpitem
->fType
& MF_SEPARATOR
)
787 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
789 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
795 if (lpitem
->hbmpItem
)
800 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
801 /* Keep the size of the bitmap in callback mode to be able
802 * to draw it correctly */
803 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
804 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
805 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
807 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
808 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
810 MenuSetRosMenuInfo(MenuInfo
);
811 itemheight
= size
.cy
+ 2;
813 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
814 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
815 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
816 lpitem
->dxTab
= lpitem
->Rect
.right
;
817 lpitem
->Rect
.right
+= check_bitmap_width
;
818 } else /* hbmpItem & MenuBar */ {
819 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
820 lpitem
->Rect
.right
+= size
.cx
;
821 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
822 itemheight
= size
.cy
;
824 /* Special case: Minimize button doesn't have a space behind it. */
825 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
826 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
827 lpitem
->Rect
.right
-= 1;
831 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
832 lpitem
->Rect
.right
+= check_bitmap_width
;
833 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
834 lpitem
->dxTab
= lpitem
->Rect
.right
;
835 lpitem
->Rect
.right
+= check_bitmap_width
;
838 /* it must be a text item - unless it's the system menu */
839 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
840 HFONT hfontOld
= NULL
;
841 RECT rc
= lpitem
->Rect
;
842 LONG txtheight
, txtwidth
;
844 if ( lpitem
->fState
& MFS_DEFAULT
) {
845 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
848 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
849 DT_SINGLELINE
|DT_CALCRECT
);
850 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
851 itemheight
= max( max( itemheight
, txtheight
),
852 GetSystemMetrics( SM_CYMENU
) - 1);
853 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
855 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
858 int n
= (int)( p
- lpitem
->dwTypeData
);
859 /* Item contains a tab (only meaningful in popup menus) */
860 /* get text size before the tab */
861 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
862 DT_SINGLELINE
|DT_CALCRECT
);
863 txtwidth
= rc
.right
- rc
.left
;
864 p
+= 1; /* advance past the Tab */
865 /* get text size after the tab */
866 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
867 DT_SINGLELINE
|DT_CALCRECT
);
868 lpitem
->dxTab
+= txtwidth
;
869 txtheight
= max( txtheight
, tmpheight
);
870 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
871 tmprc
.right
- tmprc
.left
; /* space for the short cut */
873 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
874 DT_SINGLELINE
|DT_CALCRECT
);
875 txtwidth
= rc
.right
- rc
.left
;
876 lpitem
->dxTab
+= txtwidth
;
878 lpitem
->Rect
.right
+= 2 + txtwidth
;
879 itemheight
= max( itemheight
,
880 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
882 if (hfontOld
) SelectObject (hdc
, hfontOld
);
883 } else if( menuBar
) {
884 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
886 lpitem
->Rect
.bottom
+= itemheight
;
887 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
890 /***********************************************************************
891 * MenuPopupMenuCalcSize
893 * Calculate the size of a popup menu.
895 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
897 ROSMENUITEMINFO lpitem
;
900 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
902 MenuInfo
->Width
= MenuInfo
->Height
= 0;
903 if (MenuInfo
->MenuItemCount
== 0)
905 MenuSetRosMenuInfo(MenuInfo
);
910 SelectObject( hdc
, hMenuFont
);
915 MenuInfo
->maxBmpSize
.cx
= 0;
916 MenuInfo
->maxBmpSize
.cy
= 0;
918 MenuInitRosMenuItemInfo(&lpitem
);
919 while (start
< MenuInfo
->MenuItemCount
)
924 maxTab
= maxTabWidth
= 0;
926 /* Parse items until column break or end of menu */
927 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
929 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
931 MenuCleanupRosMenuItemInfo(&lpitem
);
932 MenuSetRosMenuInfo(MenuInfo
);
936 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
938 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
939 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
941 MenuCleanupRosMenuItemInfo(&lpitem
);
942 MenuSetRosMenuInfo(MenuInfo
);
945 // Not sure here,, The patch from wine removes this.
946 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
950 maxX
= max(maxX
, lpitem
.Rect
.right
);
951 orgY
= lpitem
.Rect
.bottom
;
952 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
954 maxTab
= max( maxTab
, lpitem
.dxTab
);
955 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
959 /* Finish the column (set all items to the largest width found) */
960 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
963 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
965 lpitem
.Rect
.right
= maxX
;
966 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
968 lpitem
.dxTab
= maxTab
;
970 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
974 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
977 MenuInfo
->Width
= maxX
;
979 /* space for 3d border */
980 MenuInfo
->Height
+= 2;
981 MenuInfo
->Width
+= 2;
983 MenuCleanupRosMenuItemInfo(&lpitem
);
984 MenuSetRosMenuInfo(MenuInfo
);
988 /***********************************************************************
989 * MenuMenuBarCalcSize
991 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
992 * height is off by 1 pixel which causes lengthy window relocations when
993 * active document window is maximized/restored.
995 * Calculate the size of the menu bar.
997 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
998 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1000 ROSMENUITEMINFO ItemInfo
;
1001 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1003 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1004 if (MenuInfo
->MenuItemCount
== 0) return;
1005 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1006 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1007 MenuInfo
->Height
= 0;
1008 maxY
= lprect
->top
+ 1;
1012 MenuInfo
->maxBmpSize
.cx
= 0;
1013 MenuInfo
->maxBmpSize
.cy
= 0;
1015 MenuInitRosMenuItemInfo(&ItemInfo
);
1016 while (start
< MenuInfo
->MenuItemCount
)
1018 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1020 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1023 orgX
= lprect
->left
;
1026 /* Parse items until line break or end of menu */
1027 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1029 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1031 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1033 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1034 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1035 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1037 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1041 if (ItemInfo
.Rect
.right
> lprect
->right
)
1043 if (i
!= start
) break;
1044 else ItemInfo
.Rect
.right
= lprect
->right
;
1046 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1047 orgX
= ItemInfo
.Rect
.right
;
1048 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1050 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1052 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1058 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1059 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1061 /* Finish the line (set all items to the largest height found) */
1064 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1066 ItemInfo
.Rect
.bottom
= maxY
;
1067 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1072 start
= i
; /* This works! */
1076 lprect
->bottom
= maxY
;
1077 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1078 MenuSetRosMenuInfo(MenuInfo
);
1082 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1083 /* the last item (if several lines, only move the last line) */
1084 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1086 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1089 orgY
= ItemInfo
.Rect
.top
;
1090 orgX
= lprect
->right
;
1091 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1097 if (ItemInfo
.Rect
.top
!= orgY
)
1099 break; /* Other line */
1101 if (orgX
<= ItemInfo
.Rect
.right
)
1103 break; /* Too far right already */
1105 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1106 ItemInfo
.Rect
.right
= orgX
;
1107 orgX
= ItemInfo
.Rect
.left
;
1108 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1109 if (helpPos
+ 1 <= i
&&
1110 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1112 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1118 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1121 /***********************************************************************
1124 * Draw a single menu item.
1126 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1127 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1131 BOOL flat_menu
= FALSE
;
1133 PWND Wnd
= ValidateHwnd(hWnd
);
1138 if (lpitem
->fType
& MF_SYSMENU
)
1140 if ( (Wnd
->style
& WS_MINIMIZE
))
1142 UserGetInsideRectNC(Wnd
, &rect
);
1143 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1144 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1149 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1150 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1154 if (lpitem
->fState
& MF_HILITE
)
1156 if(menuBar
&& !flat_menu
) {
1157 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1158 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1160 if (lpitem
->fState
& MF_GRAYED
)
1161 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1163 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1164 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1169 if (lpitem
->fState
& MF_GRAYED
)
1170 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1172 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1173 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1176 rect
= lpitem
->Rect
;
1178 if (lpitem
->fType
& MF_OWNERDRAW
)
1181 ** Experimentation under Windows reveals that an owner-drawn
1182 ** menu is given the rectangle which includes the space it requested
1183 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1184 ** and a popup-menu arrow. This is the value of lpitem->rect.
1185 ** Windows will leave all drawing to the application except for
1186 ** the popup-menu arrow. Windows always draws that itself, after
1187 ** the menu owner has finished drawing.
1191 dis
.CtlType
= ODT_MENU
;
1193 dis
.itemID
= lpitem
->wID
;
1194 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1196 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1197 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1198 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1199 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1200 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1203 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1204 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1205 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1206 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1208 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1209 /* Draw the popup-menu arrow */
1210 if (lpitem
->fType
& MF_POPUP
)
1213 CopyRect(&rectTemp
, &rect
);
1214 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1215 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1220 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1222 if (lpitem
->fState
& MF_HILITE
)
1226 InflateRect (&rect
, -1, -1);
1227 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1228 InflateRect (&rect
, 1, 1);
1229 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1234 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1236 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1240 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1242 SetBkMode( hdc
, TRANSPARENT
);
1244 /* vertical separator */
1245 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1252 rc
.bottom
= Height
- 3;
1255 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1256 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1257 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1258 LineTo( hdc
, rc
.left
, rc
.bottom
);
1259 SelectObject( hdc
, oldPen
);
1262 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1265 /* horizontal separator */
1266 if (lpitem
->fType
& MF_SEPARATOR
)
1273 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1276 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1277 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1278 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1279 LineTo( hdc
, rc
.right
, rc
.top
);
1280 SelectObject( hdc
, oldPen
);
1283 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1288 /* helper lines for debugging */
1289 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1290 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1291 SelectObject(hdc
, GetStockObject(DC_PEN
));
1292 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1293 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1294 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1300 INT y
= rect
.top
+ rect
.bottom
;
1302 int checked
= FALSE
;
1303 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1304 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1305 /* Draw the check mark
1308 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1310 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1311 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1312 lpitem
->hbmpUnchecked
;
1313 if (bm
) /* we have a custom bitmap */
1315 HDC hdcMem
= CreateCompatibleDC( hdc
);
1317 SelectObject( hdcMem
, bm
);
1318 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1319 check_bitmap_width
, check_bitmap_height
,
1320 hdcMem
, 0, 0, SRCCOPY
);
1324 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1327 CopyRect(&r
, &rect
);
1328 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1329 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1330 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1331 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1335 if ( lpitem
->hbmpItem
)
1338 CopyRect(&bmpRect
, &rect
);
1339 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1340 bmpRect
.left
+= check_bitmap_width
+ 2;
1341 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1343 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1344 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1347 /* Draw the popup-menu arrow */
1348 if (lpitem
->fType
& MF_POPUP
)
1351 CopyRect(&rectTemp
, &rect
);
1352 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1353 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1356 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1357 rect
.left
+= check_bitmap_width
;
1358 rect
.right
-= check_bitmap_width
;
1360 else if( lpitem
->hbmpItem
)
1361 { /* Draw the bitmap */
1362 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1365 /* process text if present */
1371 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1372 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1374 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1375 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1377 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1379 if ( lpitem
->fState
& MFS_DEFAULT
)
1381 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1385 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1386 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1389 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1392 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1393 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1397 if(lpitem
->fState
& MF_GRAYED
)
1399 if (!(lpitem
->fState
& MF_HILITE
) )
1401 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1402 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1403 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1404 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1406 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1409 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1411 /* paint the shortcut text */
1412 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1414 if (L
'\t' == Text
[i
])
1416 rect
.left
= lpitem
->dxTab
;
1417 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1421 rect
.right
= lpitem
->dxTab
;
1422 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1425 if (lpitem
->fState
& MF_GRAYED
)
1427 if (!(lpitem
->fState
& MF_HILITE
) )
1429 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1430 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1431 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1432 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1434 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1436 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1440 SelectObject (hdc
, hfontOld
);
1444 /***********************************************************************
1447 * Paint a popup menu.
1449 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1451 HBRUSH hPrevBrush
= 0;
1454 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1456 GetClientRect( hwnd
, &rect
);
1458 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1459 && (SelectObject( hdc
, hMenuFont
)))
1463 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1465 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1468 BOOL flat_menu
= FALSE
;
1469 ROSMENUINFO MenuInfo
;
1470 ROSMENUITEMINFO ItemInfo
;
1472 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1474 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1476 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1478 /* draw menu items */
1479 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1483 MenuInitRosMenuItemInfo(&ItemInfo
);
1485 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1487 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1489 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1490 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1494 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1498 SelectObject( hdc
, hPrevBrush
);
1503 /***********************************************************************
1506 * Paint a menu bar. Returns the height of the menu bar.
1507 * called from [windows/nonclient.c]
1509 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1514 HMENU hMenu
= GetMenu(hwnd
);
1516 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1518 return GetSystemMetrics(SM_CYMENU
);
1523 hfontOld
= SelectObject(hDC
, hMenuFont
);
1525 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1527 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1529 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1530 return lppop
.Height
;
1533 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1536 /***********************************************************************
1539 * Display a popup menu.
1541 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1542 INT x
, INT y
, INT xanchor
, INT yanchor
)
1544 ROSMENUINFO MenuInfo
;
1545 ROSMENUITEMINFO ItemInfo
;
1551 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1552 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1554 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1555 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1557 MenuInitRosMenuItemInfo(&ItemInfo
);
1558 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1560 ItemInfo
.fMask
|= MIIM_STATE
;
1561 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1562 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1564 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1565 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1568 /* store the owner for DrawItem */
1569 if (!IsWindow(hwndOwner
))
1571 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1574 MenuInfo
.WndOwner
= hwndOwner
;
1575 MenuSetRosMenuInfo(&MenuInfo
);
1577 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1579 /* adjust popup menu pos so that it fits within the desktop */
1581 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1582 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1584 /* FIXME: should use item rect */
1587 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1588 info
.cbSize
= sizeof(info
);
1589 GetMonitorInfoW( monitor
, &info
);
1591 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1592 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1594 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1595 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1597 if( x
+ width
> info
.rcMonitor
.right
)
1599 if( xanchor
&& x
>= width
- xanchor
)
1600 x
-= width
- xanchor
;
1602 if( x
+ width
> info
.rcMonitor
.right
)
1603 x
= info
.rcMonitor
.right
- width
;
1605 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
1607 if( y
+ height
> info
.rcMonitor
.bottom
)
1609 if( yanchor
&& y
>= height
+ yanchor
)
1610 y
-= height
+ yanchor
;
1612 if( y
+ height
> info
.rcMonitor
.bottom
)
1613 y
= info
.rcMonitor
.bottom
- height
;
1615 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
1617 /* NOTE: In Windows, top menu popup is not owned. */
1618 MenuInfo
.Wnd
= CreateWindowExW( 0, WC_MENU
, NULL
,
1619 WS_POPUP
, x
, y
, width
, height
,
1620 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1621 (LPVOID
) MenuInfo
.Self
);
1622 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1624 top_popup
= MenuInfo
.Wnd
;
1625 top_popup_hmenu
= hmenu
;
1628 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1630 /* Display the window */
1632 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1633 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1634 UpdateWindow( MenuInfo
.Wnd
);
1639 /***********************************************************************
1642 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1643 BOOL sendMenuSelect
, HMENU topmenu
)
1645 ROSMENUITEMINFO ItemInfo
;
1646 ROSMENUINFO TopMenuInfo
;
1649 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1651 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1652 if (hmenu
->FocusedItem
== wIndex
) return;
1653 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1654 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1656 top_popup
= hmenu
->Wnd
;
1657 top_popup_hmenu
= hmenu
->Self
;
1660 SelectObject( hdc
, hMenuFont
);
1662 MenuInitRosMenuItemInfo(&ItemInfo
);
1664 /* Clear previous highlighted item */
1665 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1667 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1669 ItemInfo
.fMask
|= MIIM_STATE
;
1670 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1671 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1673 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1674 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1678 /* Highlight new item (if any) */
1679 hmenu
->FocusedItem
= wIndex
;
1680 MenuSetRosMenuInfo(hmenu
);
1681 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1683 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1685 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1687 ItemInfo
.fMask
|= MIIM_STATE
;
1688 ItemInfo
.fState
|= MF_HILITE
;
1689 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1690 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1691 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1696 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1697 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1698 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1699 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1703 else if (sendMenuSelect
) {
1706 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1707 if (pos
!= NO_SELECTED_ITEM
)
1709 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1710 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1712 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1713 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1715 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1721 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1722 ReleaseDC(hmenu
->Wnd
, hdc
);
1725 /***********************************************************************
1728 * Moves currently selected item according to the Offset parameter.
1729 * If there is no selection then it should select the last item if
1730 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1732 static void FASTCALL
1733 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1736 ROSMENUITEMINFO ItemInfo
;
1739 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1741 /* Prevent looping */
1742 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1744 else if (Offset
< -1)
1746 else if (Offset
> 1)
1749 MenuInitRosMenuItemInfo(&ItemInfo
);
1751 OrigPos
= MenuInfo
->FocusedItem
;
1752 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1759 i
= MenuInfo
->FocusedItem
;
1766 /* Clip and wrap around */
1769 i
= MenuInfo
->MenuItemCount
- 1;
1771 else if (i
>= MenuInfo
->MenuItemCount
)
1775 /* If this is a good candidate; */
1776 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1777 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1779 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1780 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1783 } while (i
!= OrigPos
);
1786 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1790 // This breaks some test results. Should handle A2U if called!
1792 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1797 pWnd
= ValidateHwnd(Wnd
);
1802 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1806 if (pWnd
->fnid
!= FNID_MENU
)
1808 ERR("Wrong window class for Menu!\n");
1815 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1821 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1822 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1826 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1827 return MA_NOACTIVATE
;
1832 BeginPaint(Wnd
, &ps
);
1833 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1838 case WM_PRINTCLIENT
:
1840 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1841 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1849 /* zero out global pointer in case resident popup window was destroyed. */
1850 if (Wnd
== top_popup
)
1853 top_popup_hmenu
= NULL
;
1859 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
1866 if (0 == GetWindowLongPtrA(Wnd
, 0))
1868 OutputDebugStringA("no menu to display\n");
1873 SetWindowLongPtrA(Wnd
, 0, 0);
1877 case MM_SETMENUHANDLE
:
1878 SetWindowLongPtrA(Wnd
, 0, wParam
);
1881 case MM_GETMENUHANDLE
:
1883 return GetWindowLongPtrA(Wnd
, 0);
1886 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1892 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1894 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
1897 pWnd
= ValidateHwnd(Wnd
);
1902 if (Message
!= WM_NCCREATE
)
1904 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1906 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1910 if (pWnd
->fnid
!= FNID_MENU
)
1912 ERR("Wrong window class for Menu!\n");
1919 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1925 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1926 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1930 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1931 return MA_NOACTIVATE
;
1936 BeginPaint(Wnd
, &ps
);
1937 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1942 case WM_PRINTCLIENT
:
1944 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1945 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1953 /* zero out global pointer in case resident popup window was destroyed. */
1954 if (Wnd
== top_popup
)
1957 top_popup_hmenu
= NULL
;
1964 if (0 == GetWindowLongPtrW(Wnd
, 0))
1966 OutputDebugStringA("no menu to display\n");
1971 SetWindowLongPtrW(Wnd
, 0, 0);
1975 case MM_SETMENUHANDLE
:
1976 SetWindowLongPtrW(Wnd
, 0, wParam
);
1979 case MM_GETMENUHANDLE
:
1981 return GetWindowLongPtrW(Wnd
, 0);
1984 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1990 /**********************************************************************
1991 * MENU_ParseResource
1993 * Parse a standard menu resource and add items to the menu.
1994 * Return a pointer to the end of the resource.
1996 * NOTE: flags is equivalent to the mtOption field
1998 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
2007 flags
= GET_WORD(res
);
2009 /* remove MF_END flag before passing it to AppendMenu()! */
2010 end
= (flags
& MF_END
);
2011 if(end
) flags
^= MF_END
;
2013 res
+= sizeof(WORD
);
2014 if(!(flags
& MF_POPUP
))
2017 res
+= sizeof(WORD
);
2021 res
+= strlen(str
) + 1;
2023 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
2024 if (flags
& MF_POPUP
)
2026 hSubMenu
= CreatePopupMenu();
2027 if(!hSubMenu
) return NULL
;
2028 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
2031 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
2033 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
2035 else /* Not a popup */
2040 flags
= MF_SEPARATOR
;
2044 if (*(LPCWSTR
)str
== 0)
2045 flags
= MF_SEPARATOR
;
2048 if (flags
& MF_SEPARATOR
)
2050 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2051 flags
|= MF_GRAYED
| MF_DISABLED
;
2055 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2057 AppendMenuW(hMenu
, flags
, id
,
2058 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2065 /**********************************************************************
2066 * MENUEX_ParseResource
2068 * Parse an extended menu resource and add items to the menu.
2069 * Return a pointer to the end of the resource.
2071 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2078 mii
.cbSize
= sizeof(mii
);
2079 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2080 mii
.fType
= GET_DWORD(res
);
2081 res
+= sizeof(DWORD
);
2082 mii
.fState
= GET_DWORD(res
);
2083 res
+= sizeof(DWORD
);
2084 mii
.wID
= GET_DWORD(res
);
2085 res
+= sizeof(DWORD
);
2086 resinfo
= GET_WORD(res
);
2087 res
+= sizeof(WORD
);
2088 /* Align the text on a word boundary. */
2089 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2090 mii
.dwTypeData
= (LPWSTR
)res
;
2091 mii
.cch
= strlenW(mii
.dwTypeData
);
2092 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2093 /* Align the following fields on a dword boundary. */
2094 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2096 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2097 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2099 if (resinfo
& 1) /* Pop-up? */
2101 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2102 res
+= sizeof(DWORD
);
2103 mii
.hSubMenu
= CreatePopupMenu();
2106 ERR("CreatePopupMenu failed\n");
2110 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2112 ERR("MENUEX_ParseResource failed\n");
2113 DestroyMenu(mii
.hSubMenu
);
2116 mii
.fMask
|= MIIM_SUBMENU
;
2117 mii
.fType
|= MF_POPUP
;
2118 mii
.wID
= (UINT
)mii
.hSubMenu
;
2120 else if (!mii
.dwTypeData
[0])
2121 mii
.fType
|= MF_SEPARATOR
;
2123 if (!InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
))
2124 ERR("InsertMenuItemW failed\n");
2125 } while (!(resinfo
& MF_END
));
2130 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2132 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2133 LRESULT Result
= (LRESULT
)hmenu
;
2134 MENUINFO menuinfo
= {0};
2135 MENUITEMINFOW info
= {0};
2137 // removing space for checkboxes from menu
2138 menuinfo
.cbSize
= sizeof(menuinfo
);
2139 menuinfo
.fMask
= MIM_STYLE
;
2140 GetMenuInfo(hmenu
, &menuinfo
);
2141 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2142 SetMenuInfo(hmenu
, &menuinfo
);
2144 // adding bitmaps to menu items
2145 info
.cbSize
= sizeof(info
);
2146 info
.fMask
|= MIIM_BITMAP
;
2147 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2148 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2149 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2150 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2151 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2152 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2153 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2154 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2156 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2163 NONCLIENTMETRICSW ncm
;
2165 /* get the menu font */
2166 if(!hMenuFont
|| !hMenuFontBold
)
2168 ncm
.cbSize
= sizeof(ncm
);
2169 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2171 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2175 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2176 if(hMenuFont
== NULL
)
2178 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2182 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2183 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2184 if(hMenuFontBold
== NULL
)
2186 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2187 DeleteObject(hMenuFont
);
2201 DeleteObject(hMenuFont
);
2207 DeleteObject(hMenuFontBold
);
2208 hMenuFontBold
= NULL
;
2212 /***********************************************************************
2213 * DrawMenuBarTemp (USER32.@)
2217 * called by W98SE desk.cpl Control Panel Applet
2219 * Not 100% sure about the param names, but close.
2224 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2226 ROSMENUINFO MenuInfo
;
2227 ROSMENUITEMINFO ItemInfo
;
2229 HFONT FontOld
= NULL
;
2230 BOOL flat_menu
= FALSE
;
2232 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2236 Menu
= GetMenu(Wnd
);
2244 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2246 return GetSystemMetrics(SM_CYMENU
);
2249 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2251 FontOld
= SelectObject(DC
, Font
);
2253 if (0 == MenuInfo
.Height
)
2255 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2258 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2260 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2262 SelectObject(DC
, GetStockObject(DC_PEN
));
2263 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2264 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2265 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2267 if (0 == MenuInfo
.MenuItemCount
)
2269 SelectObject(DC
, FontOld
);
2270 return GetSystemMetrics(SM_CYMENU
);
2273 MenuInitRosMenuItemInfo(&ItemInfo
);
2274 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2276 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2278 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2279 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2282 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2284 SelectObject(DC
, FontOld
);
2286 return MenuInfo
.Height
;
2289 /***********************************************************************
2292 * Display the sub-menu of the selected item of this menu.
2293 * Return the handle of the submenu, or menu if no submenu to display.
2295 static HMENU FASTCALL
2296 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2298 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2300 ROSMENUITEMINFO ItemInfo
;
2301 ROSMENUINFO SubMenuInfo
;
2305 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2307 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2309 return MenuInfo
->Self
;
2312 MenuInitRosMenuItemInfo(&ItemInfo
);
2313 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2315 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2316 return MenuInfo
->Self
;
2318 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2320 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2321 return MenuInfo
->Self
;
2324 /* message must be sent before using item,
2325 because nearly everything may be changed by the application ! */
2327 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2328 if (0 == (Flags
& TPM_NONOTIFY
))
2330 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2331 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2334 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2336 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2337 return MenuInfo
->Self
;
2339 Rect
= ItemInfo
.Rect
;
2341 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2342 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2344 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2346 Dc
= GetDC(MenuInfo
->Wnd
);
2350 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2353 SelectObject(Dc
, hMenuFont
);
2354 ItemInfo
.fMask
|= MIIM_STATE
;
2355 ItemInfo
.fState
|= MF_HILITE
;
2356 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2357 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2358 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2359 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2362 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2363 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2365 ItemInfo
.Rect
= Rect
;
2368 ItemInfo
.fMask
|= MIIM_STATE
;
2369 ItemInfo
.fState
|= MF_MOUSESELECT
;
2370 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2372 if (IS_SYSTEM_MENU(MenuInfo
))
2374 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2375 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2377 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2378 Rect
.top
= Rect
.bottom
;
2379 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2380 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2384 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2385 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2387 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2388 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2389 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2390 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2391 - GetSystemMetrics(SM_CYBORDER
);
2395 Rect
.left
+= ItemInfo
.Rect
.left
;
2396 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2397 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2398 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2402 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2403 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2404 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2406 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2409 Ret
= ItemInfo
.hSubMenu
;
2410 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2415 /**********************************************************************
2418 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2420 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2422 void MENU_EndMenu( HWND hwnd
)
2424 ROSMENUINFO MenuInfo
;
2426 if (top_popup_hmenu
)
2427 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2428 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2431 /***********************************************************************
2434 * Hide the sub-popup menus of this menu.
2436 static void FASTCALL
2437 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2438 BOOL SendMenuSelect
, UINT wFlags
)
2440 ROSMENUINFO SubMenuInfo
;
2441 ROSMENUITEMINFO ItemInfo
;
2443 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2445 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2447 MenuInitRosMenuItemInfo(&ItemInfo
);
2448 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2449 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2450 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2451 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2453 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2456 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2457 ItemInfo
.fMask
|= MIIM_STATE
;
2458 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2459 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2461 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2462 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2463 DestroyWindow(SubMenuInfo
.Wnd
);
2464 SubMenuInfo
.Wnd
= NULL
;
2465 MenuSetRosMenuInfo(&SubMenuInfo
);
2467 if (!(wFlags
& TPM_NONOTIFY
))
2468 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2469 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2474 /***********************************************************************
2475 * MenuSwitchTracking
2477 * Helper function for menu navigation routines.
2479 static void FASTCALL
2480 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2482 ROSMENUINFO TopMenuInfo
;
2484 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2486 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2487 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2488 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2490 /* both are top level menus (system and menu-bar) */
2491 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2492 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2493 Mt
->TopMenu
= PtMenuInfo
->Self
;
2497 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2500 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2503 /***********************************************************************
2504 * MenuExecFocusedItem
2506 * Execute a menu item (for instance when user pressed Enter).
2507 * Return the wID of the executed item. Otherwise, -1 indicating
2508 * that no menu item was executed, -2 if a popup is shown;
2509 * Have to receive the flags for the TrackPopupMenu options to avoid
2510 * sending unwanted message.
2514 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2516 ROSMENUITEMINFO ItemInfo
;
2519 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2521 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2526 MenuInitRosMenuItemInfo(&ItemInfo
);
2527 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2529 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2533 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2535 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2537 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2538 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2540 /* If TPM_RETURNCMD is set you return the id, but
2541 do not send a message to the owner */
2542 if (0 == (Flags
& TPM_RETURNCMD
))
2544 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2546 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2547 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2551 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2552 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2553 MenuInfo
->FocusedItem
,
2554 (LPARAM
)MenuInfo
->Self
);
2556 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2560 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2566 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2573 /***********************************************************************
2576 * Return TRUE if we can go on with menu tracking.
2578 static BOOL FASTCALL
2579 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2582 ROSMENUINFO MenuInfo
;
2583 ROSMENUITEMINFO Item
;
2585 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2589 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2593 if (IS_SYSTEM_MENU(&MenuInfo
))
2599 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2601 MenuInitRosMenuItemInfo(&Item
);
2602 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2604 MenuCleanupRosMenuItemInfo(&Item
);
2608 if (!(Item
.fType
& MF_SEPARATOR
) &&
2609 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2611 if (MenuInfo
.FocusedItem
!= Index
)
2613 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2616 /* If the popup menu is not already "popped" */
2617 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2619 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2623 MenuCleanupRosMenuItemInfo(&Item
);
2628 /* else the click was on the menu bar, finish the tracking */
2633 /***********************************************************************
2636 * Return the value of MenuExecFocusedItem if
2637 * the selected item was not a popup. Else open the popup.
2638 * A -1 return value indicates that we go on with menu tracking.
2642 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2645 ROSMENUINFO MenuInfo
;
2646 ROSMENUITEMINFO ItemInfo
;
2648 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2653 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2658 if (! IS_SYSTEM_MENU(&MenuInfo
))
2660 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2662 MenuInitRosMenuItemInfo(&ItemInfo
);
2663 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2664 MenuInfo
.FocusedItem
== Id
)
2666 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2668 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2669 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2670 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2672 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2674 /* If we are dealing with the top-level menu */
2675 /* and this is a click on an already "popped" item: */
2676 /* Stop the menu tracking and close the opened submenus */
2677 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2679 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2683 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2684 MenuInfo
.TimeToHide
= TRUE
;
2685 MenuSetRosMenuInfo(&MenuInfo
);
2691 /***********************************************************************
2694 * Walks menu chain trying to find a menu pt maps to.
2696 static HMENU FASTCALL
2697 MenuPtMenu(HMENU Menu
, POINT Pt
)
2699 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2700 ROSMENUINFO MenuInfo
;
2701 ROSMENUITEMINFO ItemInfo
;
2705 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2710 /* try subpopup first (if any) */
2711 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2713 MenuInitRosMenuItemInfo(&ItemInfo
);
2714 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2715 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2716 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2718 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2721 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2725 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2728 /* check the current window (avoiding WM_HITTEST) */
2729 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2730 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2732 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2737 else if (HTSYSMENU
== Ht
)
2739 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2741 else if (HTMENU
== Ht
)
2743 Ret
= GetMenu(MenuInfo
.Wnd
);
2749 /***********************************************************************
2752 * Return TRUE if we can go on with menu tracking.
2754 static BOOL FASTCALL
2755 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2758 ROSMENUINFO MenuInfo
;
2759 ROSMENUITEMINFO ItemInfo
;
2763 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2767 if (IS_SYSTEM_MENU(&MenuInfo
))
2773 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2778 Index
= NO_SELECTED_ITEM
;
2781 if (NO_SELECTED_ITEM
== Index
)
2783 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2784 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2786 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2790 else if (MenuInfo
.FocusedItem
!= Index
)
2792 MenuInitRosMenuItemInfo(&ItemInfo
);
2793 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2794 !(ItemInfo
.fType
& MF_SEPARATOR
))
2796 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2797 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2798 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2800 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2806 /***********************************************************************
2809 * Return the handle of the selected sub-popup menu (if any).
2811 static HMENU FASTCALL
2812 MenuGetSubPopup(HMENU Menu
)
2814 ROSMENUINFO MenuInfo
;
2815 ROSMENUITEMINFO ItemInfo
;
2817 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2818 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2823 MenuInitRosMenuItemInfo(&ItemInfo
);
2824 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2826 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2829 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2831 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2832 return ItemInfo
.hSubMenu
;
2835 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2839 /***********************************************************************
2842 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2844 static LRESULT FASTCALL
2845 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2847 ROSMENUINFO TopMenuInfo
;
2848 ROSMENUINFO MenuInfo
;
2850 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2852 return (LRESULT
) FALSE
;
2855 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2856 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2858 MDINEXTMENU NextMenu
;
2863 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2864 NextMenu
.hmenuNext
= NULL
;
2865 NextMenu
.hwndNext
= NULL
;
2866 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2868 TRACE("%p [%p] -> %p [%p]\n",
2869 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2871 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2873 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2874 NewWnd
= Mt
->OwnerWnd
;
2875 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2877 /* switch to the menu bar */
2879 if (0 != (Style
& WS_CHILD
)
2880 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2887 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2891 Id
= MenuInfo
.MenuItemCount
- 1;
2894 else if (0 != (Style
& WS_SYSMENU
))
2896 /* switch to the system menu */
2897 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2904 else /* application returned a new menu to switch to */
2906 NewMenu
= NextMenu
.hmenuNext
;
2907 NewWnd
= NextMenu
.hwndNext
;
2909 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2911 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2913 if (0 != (Style
& WS_SYSMENU
)
2914 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2916 /* get the real system menu */
2917 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2919 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2921 /* FIXME: Not sure what to do here;
2922 * perhaps try to track NewMenu as a popup? */
2924 WARN(" -- got confused.\n");
2934 if (NewMenu
!= Mt
->TopMenu
)
2936 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2938 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2940 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2944 if (NewWnd
!= Mt
->OwnerWnd
)
2946 Mt
->OwnerWnd
= NewWnd
;
2947 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
2948 SetCapture(Mt
->OwnerWnd
); // 2
2951 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2952 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2954 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2963 /***********************************************************************
2966 * The idea is not to show the popup if the next input message is
2967 * going to hide it anyway.
2969 static BOOL FASTCALL
2970 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
2974 msg
.hwnd
= Mt
->OwnerWnd
;
2976 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
2977 // Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
2982 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2983 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2985 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2986 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2987 if( msg
.message
== WM_KEYDOWN
&&
2988 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2990 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2996 /* failures go through this */
2997 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3001 /***********************************************************************
3004 * Handle a VK_ESCAPE key event in a menu.
3006 static BOOL FASTCALL
3007 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3009 BOOL EndMenu
= TRUE
;
3010 ROSMENUINFO MenuInfo
;
3011 HMENU MenuTmp
, MenuPrev
;
3013 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3015 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3016 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
3018 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3020 /* close topmost popup */
3021 while (MenuTmp
!= Mt
->CurrentMenu
)
3024 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3027 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3029 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3031 Mt
->CurrentMenu
= MenuPrev
;
3039 /***********************************************************************
3042 * Handle a VK_LEFT key event in a menu.
3044 static void FASTCALL
3045 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3047 ROSMENUINFO MenuInfo
;
3048 ROSMENUINFO TopMenuInfo
;
3049 ROSMENUINFO PrevMenuInfo
;
3050 HMENU MenuTmp
, MenuPrev
;
3053 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3055 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3060 /* Try to move 1 column left (if possible) */
3061 if ( (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)) != NO_SELECTED_ITEM
)
3063 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3065 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3070 /* close topmost popup */
3071 while (MenuTmp
!= Mt
->CurrentMenu
)
3074 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3077 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3081 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3082 Mt
->CurrentMenu
= MenuPrev
;
3084 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3088 if ((MenuPrev
== Mt
->TopMenu
) && !(TopMenuInfo
.Flags
& MF_POPUP
))
3090 /* move menu bar selection if no more popups are left */
3092 if (!MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3094 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3097 if (MenuPrev
!= MenuTmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3099 /* A sublevel menu was displayed - display the next one
3100 * unless there is another displacement coming up */
3102 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3103 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3105 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3112 /***********************************************************************
3115 * Handle a VK_RIGHT key event in a menu.
3117 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3120 ROSMENUINFO MenuInfo
;
3121 ROSMENUINFO CurrentMenuInfo
;
3124 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3125 Mt
->CurrentMenu
, Mt
->TopMenu
);
3127 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3128 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3130 /* If already displaying a popup, try to display sub-popup */
3132 hmenutmp
= Mt
->CurrentMenu
;
3133 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3135 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3138 /* if subpopup was displayed then we are done */
3139 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3142 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3147 /* Check to see if there's another column */
3148 if ( (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)) != NO_SELECTED_ITEM
)
3150 TRACE("Going to %d.\n", NextCol
);
3151 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3153 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3158 if (!(MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3160 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3162 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3163 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3170 /* try to move to the next item */
3171 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3172 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3174 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3176 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3177 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3179 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3186 /***********************************************************************
3189 * Menu tracking code.
3191 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3192 HWND hwnd
, const RECT
*lprect
)
3195 ROSMENUINFO MenuInfo
;
3196 ROSMENUITEMINFO ItemInfo
;
3198 INT executedMenuId
= -1;
3201 BOOL enterIdleSent
= FALSE
;
3204 mt
.CurrentMenu
= hmenu
;
3210 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3211 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3212 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3216 WARN("Invalid menu handle %p\n", hmenu
);
3217 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3222 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3227 if (wFlags
& TPM_BUTTONDOWN
)
3229 /* Get the result in order to start the tracking or not */
3230 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3231 fEndMenu
= !fRemove
;
3234 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3236 /* owner may not be visible when tracking a popup, so use the menu itself */
3237 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3238 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3239 SetCapture(capture_win
); // 2
3243 BOOL ErrorExit
= FALSE
;
3244 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, TYPE_MENU
);
3245 if (!menu
) /* sometimes happens if I do a window manager close */
3248 /* we have to keep the message in the queue until it's
3249 * clear that menu loop is not over yet. */
3253 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3255 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3256 /* remove the message from the queue */
3257 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3262 if (!ValidateHwnd(mt
.OwnerWnd
) || !ValidateHwnd(MenuInfo
.Wnd
))
3264 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3269 HWND win
= MenuInfo
.Flags
& MF_POPUP
? MenuInfo
.Wnd
: NULL
;
3270 enterIdleSent
= TRUE
;
3271 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3277 if (ErrorExit
) break; // Gracefully dropout.
3279 /* check if EndMenu() tried to cancel us, by posting this message */
3280 if (msg
.message
== WM_CANCELMODE
)
3282 /* we are now out of the loop */
3285 /* remove the message from the queue */
3286 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3288 /* break out of internal loop, ala ESCAPE */
3292 TranslateMessage( &msg
);
3295 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3296 enterIdleSent
=FALSE
;
3299 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3302 * Use the mouse coordinates in lParam instead of those in the MSG
3303 * struct to properly handle synthetic messages. They are already
3304 * in screen coordinates.
3306 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3307 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3309 /* Find a menu for this mouse event */
3310 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3314 /* no WM_NC... messages in captured state */
3316 case WM_RBUTTONDBLCLK
:
3317 case WM_RBUTTONDOWN
:
3318 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3320 case WM_LBUTTONDBLCLK
:
3321 case WM_LBUTTONDOWN
:
3322 /* If the message belongs to the menu, removes it from the queue */
3323 /* Else, end menu tracking */
3324 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3325 fEndMenu
= !fRemove
;
3329 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3332 /* Check if a menu was selected by the mouse */
3335 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3336 TRACE("executedMenuId %d\n", executedMenuId
);
3338 /* End the loop if executedMenuId is an item ID */
3339 /* or if the job was done (executedMenuId = 0). */
3340 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3342 /* No menu was selected by the mouse */
3343 /* if the function was called by TrackPopupMenu, continue
3344 with the menu tracking. If not, stop it */
3346 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3351 /* the selected menu item must be changed every time */
3352 /* the mouse moves. */
3355 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3357 } /* switch(msg.message) - mouse */
3359 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3361 fRemove
= TRUE
; /* Keyboard messages are always removed */
3375 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3377 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
3378 NO_SELECTED_ITEM
, FALSE
, 0 );
3379 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3380 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3385 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3386 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3388 if (!(MenuInfo
.Flags
& MF_POPUP
))
3390 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3391 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3393 else /* otherwise try to move selection */
3394 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3395 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3400 MenuKeyLeft( &mt
, wFlags
);
3404 MenuKeyRight( &mt
, wFlags
);
3408 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3414 hi
.cbSize
= sizeof(HELPINFO
);
3415 hi
.iContextType
= HELPINFO_MENUITEM
;
3416 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3418 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
)
3422 MenuInitRosMenuItemInfo(&ItemInfo
);
3423 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3424 MenuInfo
.FocusedItem
,
3427 hi
.iCtrlId
= ItemInfo
.wID
;
3433 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3436 hi
.hItemHandle
= hmenu
;
3437 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3438 hi
.MousePos
= msg
.pt
;
3439 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3446 break; /* WM_KEYDOWN */
3453 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3454 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3456 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3457 fEndMenu
= (executedMenuId
!= -2);
3461 /* Hack to avoid control chars. */
3462 /* We will find a better way real soon... */
3463 if (msg
.wParam
< 32) break;
3465 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3466 LOWORD(msg
.wParam
), FALSE
);
3467 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3468 else if (pos
== (UINT
)-1) MessageBeep(0);
3471 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3473 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3474 fEndMenu
= (executedMenuId
!= -2);
3478 } /* switch(msg.message) - kbd */
3482 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3483 DispatchMessageW( &msg
);
3487 if (!fEndMenu
) fRemove
= TRUE
;
3489 /* finally remove message from the queue */
3491 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3492 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3493 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3496 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3497 SetCapture(NULL
); /* release the capture */
3499 /* If dropdown is still painted and the close box is clicked on
3500 then the menu will be destroyed as part of the DispatchMessage above.
3501 This will then invalidate the menu handle in mt.hTopMenu. We should
3502 check for this first. */
3503 if( IsMenu( mt
.TopMenu
) )
3505 if (IsWindow(mt
.OwnerWnd
))
3507 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3509 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3511 if (MenuInfo
.Flags
& MF_POPUP
)
3513 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3514 DestroyWindow(MenuInfo
.Wnd
);
3515 MenuInfo
.Wnd
= NULL
;
3517 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3518 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3519 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3522 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3525 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3528 /* Reset the variable for hiding menu */
3529 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3531 MenuInfo
.TimeToHide
= FALSE
;
3532 MenuSetRosMenuInfo(&MenuInfo
);
3536 /* The return value is only used by TrackPopupMenu */
3537 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3538 if (executedMenuId
== -1) executedMenuId
= 0;
3539 return executedMenuId
;
3542 /***********************************************************************
3545 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3547 ROSMENUINFO MenuInfo
;
3549 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3553 /* This makes the menus of applications built with Delphi work.
3554 * It also enables menus to be displayed in more than one window,
3555 * but there are some bugs left that need to be fixed in this case.
3557 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
3559 MenuInfo
.Wnd
= hWnd
;
3560 MenuSetRosMenuInfo(&MenuInfo
);
3563 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3564 if (!(wFlags
& TPM_NONOTIFY
))
3565 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3567 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3569 if (!(wFlags
& TPM_NONOTIFY
))
3571 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3572 /* If an app changed/recreated menu bar entries in WM_INITMENU
3573 * menu sizes will be recalculated once the menu created/shown.
3576 if (!MenuInfo
.Height
)
3578 /* app changed/recreated menu bar entries in WM_INITMENU
3579 Recalculate menu sizes else clicks will not work */
3580 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3581 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3586 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
3588 MenuInfo
.Flags
& MF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
3592 /***********************************************************************
3595 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
3597 TRACE("hwnd=%p\n", hWnd
);
3599 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
3600 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
3603 top_popup_hmenu
= NULL
;
3607 /***********************************************************************
3608 * MenuTrackMouseMenuBar
3610 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3612 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3614 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3615 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3617 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3621 /* map point to parent client coordinates */
3622 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3623 if (Parent
!= GetDesktopWindow())
3625 ScreenToClient(Parent
, &pt
);
3628 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3629 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3630 MenuExitTracking(hWnd
, FALSE
);
3635 /***********************************************************************
3636 * MenuTrackKbdMenuBar
3638 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3640 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3642 UINT uItem
= NO_SELECTED_ITEM
;
3644 ROSMENUINFO MenuInfo
;
3645 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3647 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3649 /* find window that has a menu */
3651 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3652 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3653 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3655 /* check if we have to track a system menu */
3657 hTrackMenu
= GetMenu( hwnd
);
3658 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3660 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3661 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3663 wParam
|= HTSYSMENU
; /* prevent item lookup */
3666 if (!IsMenu( hTrackMenu
)) return;
3668 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3670 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3675 if( wChar
&& wChar
!= ' ' )
3677 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3678 if ( uItem
>= (UINT
)(-2) )
3680 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3681 /* schedule end of menu tracking */
3682 wFlags
|= TF_ENDMENU
;
3687 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3689 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
3691 if( uItem
== NO_SELECTED_ITEM
)
3692 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3694 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
3698 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3699 MenuExitTracking( hwnd
, FALSE
);
3702 /**********************************************************************
3703 * TrackPopupMenuEx (USER32.@)
3705 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
3706 HWND Wnd
, LPTPMPARAMS Tpm
)
3709 ROSMENUINFO MenuInfo
;
3713 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3718 if (!ValidateHwnd(Wnd
))
3723 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
3724 if (IsWindow(MenuInfo
.Wnd
))
3726 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
3730 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
3732 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3733 if (!(Flags
& TPM_NONOTIFY
))
3734 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
3736 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
3737 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
3738 Tpm
? &Tpm
->rcExclude
: NULL
);
3739 MenuExitTracking(Wnd
, TRUE
);
3743 /**********************************************************************
3744 * TrackPopupMenu (USER32.@)
3746 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
3747 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
3749 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
3754 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3755 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3757 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3759 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3760 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3761 * MFT_STRING is replaced by MIIM_STRING.
3762 * (So, I guess we should use MIIM_STRING only for strings?)
3764 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3766 * Based on wine, SetMenuItemInfo_common:
3767 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3768 * it will result in a error.
3769 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3770 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3777 LPMENUITEMINFOW mii
,
3784 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3786 if(Flags
& MF_BITMAP
)
3788 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3789 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3791 if (Flags
& MF_HELP
)
3793 /* increase ident */
3794 mii
->fType
|= MF_HELP
;
3797 else if(Flags
& MF_OWNERDRAW
)
3799 mii
->fType
|= MFT_OWNERDRAW
;
3800 mii
->fMask
|= MIIM_DATA
;
3801 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
3803 else if (Flags
& MF_SEPARATOR
)
3805 mii
->fType
|= MFT_SEPARATOR
;
3806 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3807 Flags
|= MF_GRAYED
|MF_DISABLED
;
3809 else /* Default action MF_STRING. */
3811 /* Item beginning with a backspace is a help item */
3812 if (NewItem
!= NULL
)
3816 if (*NewItem
== '\b')
3818 mii
->fType
|= MF_HELP
;
3824 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3825 if (*NewItemA
== '\b')
3827 mii
->fType
|= MF_HELP
;
3829 NewItem
= (LPCWSTR
) NewItemA
;
3833 if (Flags
& MF_HELP
)
3834 mii
->fType
|= MF_HELP
;
3835 mii
->fMask
|= MIIM_STRING
;
3836 mii
->fType
|= MFT_STRING
; /* Zero */
3837 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3839 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3841 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3845 mii
->fType
|= MFT_SEPARATOR
;
3846 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3847 Flags
|= MF_GRAYED
|MF_DISABLED
;
3851 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3853 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3856 if(Flags
& MF_MENUBREAK
)
3858 mii
->fType
|= MFT_MENUBREAK
;
3860 else if(Flags
& MF_MENUBARBREAK
)
3862 mii
->fType
|= MFT_MENUBARBREAK
;
3865 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3867 if (Flags
& MF_GRAYED
)
3868 mii
->fState
|= MF_GRAYED
;
3870 if (Flags
& MF_DISABLED
)
3871 mii
->fState
|= MF_DISABLED
;
3873 mii
->fMask
|= MIIM_STATE
;
3875 else if (Flags
& MF_HILITE
)
3877 mii
->fState
|= MF_HILITE
;
3878 mii
->fMask
|= MIIM_STATE
;
3880 else /* default state */
3882 mii
->fState
|= MFS_ENABLED
;
3883 mii
->fMask
|= MIIM_STATE
;
3886 if(Flags
& MF_POPUP
)
3888 mii
->fType
|= MF_POPUP
;
3889 mii
->fMask
|= MIIM_SUBMENU
;
3890 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3894 mii
->fMask
|= MIIM_ID
;
3895 mii
->wID
= (UINT
)IDNewItem
;
3901 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3903 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3906 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3908 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3909 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3910 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3911 (LPCWSTR
)&Common
->MenuName
);
3913 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3917 /* FUNCTIONS *****************************************************************/
3920 MenuIsStringItem(ULONG TypeData)
3922 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3930 AppendMenuA(HMENU hMenu
,
3932 UINT_PTR uIDNewItem
,
3935 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3944 AppendMenuW(HMENU hMenu
,
3946 UINT_PTR uIDNewItem
,
3949 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3958 CheckMenuItem(HMENU hmenu
,
3962 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3967 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3970 PROSMENUITEMINFO Items
= NULL
;
3971 UINT cChecked
, cUnchecked
;
3975 if(idFirst
> idLast
)
3978 ItemCount
= GetMenuItemCount(hMenu
);
3980 //mi.cbSize = sizeof(ROSMENUINFO);
3981 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3984 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3986 ERR("MenuGetAllRosMenuItemInfo failed\n");
3990 cChecked
= cUnchecked
= 0;
3992 for (i
= 0 ; i
< ItemCount
; i
++)
3995 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3996 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3998 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
4000 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
4003 if (uFlags
& MF_BYPOSITION
)
4005 if (i
< idFirst
|| i
> idLast
)
4020 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
4023 if (Items
[i
].wID
== idCheck
)
4037 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4040 Items
[i
].fType
|= MFT_RADIOCHECK
;
4041 Items
[i
].fState
|= MFS_CHECKED
;
4045 Items
[i
].fState
&= ~MFS_CHECKED
;
4048 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4050 ERR("MenuSetRosMenuItemInfo failed\n");
4055 HeapFree(GetProcessHeap(), 0, Items
);
4057 *pChecked
+= cChecked
;
4058 *pUnchecked
+= cUnchecked
;
4060 if (cChecked
|| cUnchecked
)
4070 CheckMenuRadioItem(HMENU hmenu
,
4077 UINT cUnchecked
= 0;
4078 UINT cMenuChanged
= 0;
4080 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4083 if (cMenuChanged
> 1)
4090 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4093 return (cChecked
!= 0);
4104 return NtUserxCreateMenu();
4112 CreatePopupMenu(VOID
)
4115 return NtUserxCreatePopupMenu();
4123 DrawMenuBar(HWND hWnd
)
4125 // return NtUserxDrawMenuBar(hWnd);
4126 ROSMENUINFO MenuInfo
;
4128 hMenu
= GetMenu(hWnd
);
4131 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4132 MenuInfo
.Height
= 0; // make sure to recalc size
4133 MenuSetRosMenuInfo(&MenuInfo
);
4135 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4136 SWP_NOZORDER
| SWP_FRAMECHANGED
);
4144 EnableMenuItem(HMENU hMenu
,
4148 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4158 guii
.cbSize
= sizeof(GUITHREADINFO
);
4159 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4163 guii
.hwndMenuOwner
!= top_popup
)
4165 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4169 /* if we are in the menu code, and it is active */
4170 if (!fEndMenu
&& top_popup
)
4172 /* terminate the menu handling code */
4175 /* needs to be posted to wakeup the internal menu handler */
4176 /* which will now terminate the menu, in the event that */
4177 /* the main window was minimized, or lost focus, so we */
4178 /* don't end up with an orphaned menu */
4179 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4184 // So this one maybe one day it will be a callback!
4185 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4188 ROSMENUINFO MenuInfo
;
4189 ROSMENUITEMINFO mii
;
4190 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4193 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4196 if (!NtUserMenuItemInfo(hMenu
, wItemID
, wHilite
, &mii
, FALSE
)) return FALSE
;
4197 if (!NtUserMenuInfo(hMenu
, &MenuInfo
, FALSE
)) return FALSE
;
4198 if (MenuInfo
.FocusedItem
== wItemID
) return TRUE
;
4199 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4200 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4210 PWND Wnd
= ValidateHwnd(hWnd
);
4215 return UlongToHandle(Wnd
->IDMenu
);
4222 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4225 Ret
= NtUserGetMenuBarInfo( hwnd
, idObject
, idItem
, pmbi
);
4226 // Reason to move to server side!!!!!
4227 if (!Ret
) return Ret
;
4229 pmbi
->fBarFocused
= top_popup_hmenu
== pmbi
->hMenu
;
4232 pmbi
->fFocused
= pmbi
->fBarFocused
;
4243 GetMenuCheckMarkDimensions(VOID
)
4245 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4246 GetSystemMetrics(SM_CYMENUCHECK
)));
4254 GetMenuDefaultItem(HMENU hMenu
,
4258 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4266 GetMenuInfo(HMENU hmenu
,
4272 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4275 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4276 mi
.cbSize
= sizeof(MENUINFO
);
4277 mi
.fMask
= lpcmi
->fMask
;
4279 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4281 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4290 GetMenuItemCount(HMENU Menu
)
4292 ROSMENUINFO MenuInfo
;
4294 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4302 GetMenuItemID(HMENU hMenu
,
4305 ROSMENUITEMINFO mii
;
4307 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4308 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4310 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4315 if (NULL
!= mii
.hSubMenu
)
4336 LPMENUITEMINFOA mii
)
4342 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4343 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - 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 AnsiBuffer
= mii
->dwTypeData
;
4356 Count
= miiW
.cch
= mii
->cch
;
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
);
4376 if (!AnsiBuffer
|| !Count
)
4378 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4379 mii
->dwTypeData
= AnsiBuffer
;
4380 mii
->cch
= miiW
.cch
;
4384 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4388 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4392 if (Count
> miiW
.cch
)
4394 AnsiBuffer
[miiW
.cch
] = 0;
4396 mii
->cch
= miiW
.cch
;
4404 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4405 mii
->dwTypeData
= AnsiBuffer
;
4419 LPMENUITEMINFOW mii
)
4425 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4426 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4428 SetLastError(ERROR_INVALID_PARAMETER
);
4432 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4434 /* No text requested, just pass on */
4435 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4438 String
= mii
->dwTypeData
;
4440 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4441 miiW
.dwTypeData
= 0;
4445 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4446 miiW
.cch
* sizeof(WCHAR
));
4447 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4448 miiW
.dwTypeData
[0] = 0;
4451 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4453 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4457 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4459 if (!String
|| !Count
)
4461 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4462 mii
->dwTypeData
= String
; // may not be zero.
4463 mii
->cch
= miiW
.cch
;
4467 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4469 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4472 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4473 mii
->dwTypeData
= String
;
4474 mii
->cch
= strlenW(String
);
4489 ROSMENUINFO MenuInfo
;
4490 ROSMENUITEMINFO mii
;
4491 memset( &mii
, 0, sizeof(mii
) );
4492 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4493 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4496 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4501 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4505 nSubItems
= MenuInfo
.MenuItemCount
;
4507 /* FIXME - ported from wine, does that work (0xff)? */
4508 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4509 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4511 return (UINT
)-1; /* Invalid submenu */
4514 /* FIXME - ported from wine, does that work? */
4515 return (mii
.fType
| mii
.fState
);
4535 memset( &mii
, 0, sizeof(mii
) );
4536 mii
.dwTypeData
= lpString
;
4537 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4538 mii
.fType
= MFT_STRING
;
4539 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4540 mii
.cch
= nMaxCount
;
4542 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4562 memset( &miiW
, 0, sizeof(miiW
) );
4563 miiW
.dwTypeData
= lpString
;
4564 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4565 miiW
.fType
= MFT_STRING
;
4566 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4567 miiW
.cch
= nMaxCount
;
4569 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4587 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4588 mi
.fMask
= MIIM_SUBMENU
;
4590 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4592 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4609 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4611 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4624 UINT_PTR uIDNewItem
,
4628 memset( &mii
, 0, sizeof(mii
) );
4629 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4630 mii
.fMask
= MIIM_FTYPE
;
4632 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4635 (LPCWSTR
) lpNewItem
,
4638 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4652 LPCMENUITEMINFOA lpmii
)
4655 UNICODE_STRING MenuText
;
4657 BOOL CleanHeap
= FALSE
;
4659 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4660 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4662 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4664 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4666 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4669 /* copy the text string */
4670 if (((mi
.fMask
& MIIM_STRING
) ||
4671 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4672 && mi
.dwTypeData
!= NULL
)
4674 if (!RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
))
4676 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
4679 mi
.dwTypeData
= MenuText
.Buffer
;
4680 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4683 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4685 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4700 LPCMENUITEMINFOW lpmii
)
4703 UNICODE_STRING MenuText
;
4706 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4707 if a bad user passes bad data, we crash his process instead of the
4710 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4711 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4713 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4715 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4717 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4720 /* copy the text string */
4721 if (((mi
.fMask
& MIIM_STRING
) ||
4722 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4723 && mi
.dwTypeData
!= NULL
)
4725 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4726 mi
.dwTypeData
= MenuText
.Buffer
;
4727 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4729 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4744 UINT_PTR uIDNewItem
,
4748 memset( &mii
, 0, sizeof(mii
) );
4749 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4750 mii
.fMask
= MIIM_FTYPE
;
4752 MenuSetItemData( &mii
,
4758 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4770 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
4779 LoadMenuA(HINSTANCE hInstance
,
4782 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4783 if (Resource
== NULL
)
4787 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4795 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4797 return(LoadMenuIndirectW(lpMenuTemplate
));
4805 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4808 WORD version
, offset
;
4809 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4811 version
= GET_WORD(p
);
4816 case 0: /* standard format is version of 0 */
4817 offset
= GET_WORD(p
);
4818 p
+= sizeof(WORD
) + offset
;
4819 if (!(hMenu
= CreateMenu())) return 0;
4820 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4826 case 1: /* extended format is version of 1 */
4827 offset
= GET_WORD(p
);
4828 p
+= sizeof(WORD
) + offset
;
4829 if (!(hMenu
= CreateMenu())) return 0;
4830 if (!MENUEX_ParseResource(p
, hMenu
))
4832 DestroyMenu( hMenu
);
4837 ERR("Menu template version %d not supported.\n", version
);
4847 LoadMenuW(HINSTANCE hInstance
,
4850 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4851 if (Resource
== NULL
)
4855 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4869 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4882 UINT_PTR uIDNewItem
,
4886 ROSMENUITEMINFO rmii
;
4888 memset( &mii
, 0, sizeof(mii
) );
4889 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4890 mii
.fMask
= MIIM_FTYPE
;
4892 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4896 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4898 MenuInitRosMenuItemInfo( &rmii
);
4900 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4902 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4903 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4905 MenuCleanupRosMenuItemInfo( &rmii
);
4907 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4910 (LPCWSTR
) lpNewItem
,
4913 return SetMenuItemInfoA( hMnu
,
4915 (BOOL
)(MF_BYPOSITION
& uFlags
),
4929 UINT_PTR uIDNewItem
,
4933 ROSMENUITEMINFO rmii
;
4935 memset ( &mii
, 0, sizeof(mii
) );
4936 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4937 mii
.fMask
= MIIM_FTYPE
;
4939 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4941 mi
.Height
= 0; // Force size recalculation.
4943 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4945 MenuInitRosMenuItemInfo( &rmii
);
4947 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4949 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4950 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4952 MenuCleanupRosMenuItemInfo( &rmii
);
4954 /* Init new data for this menu item */
4955 MenuSetItemData( &mii
,
4961 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4962 return SetMenuItemInfoW( hMnu
,
4964 (BOOL
)(MF_BYPOSITION
& uFlags
),
4976 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4992 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4994 SetLastError(ERROR_INVALID_PARAMETER
);
4998 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4999 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
5012 HBITMAP hBitmapUnchecked
,
5013 HBITMAP hBitmapChecked
)
5015 ROSMENUITEMINFO uItem
;
5016 memset ( &uItem
, 0, sizeof(uItem
) );
5017 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
5019 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
5020 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
5022 if (!hBitmapChecked
&& !hBitmapUnchecked
)
5024 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
5026 else /* Install new bitmaps */
5028 uItem
.hbmpChecked
= hBitmapChecked
;
5029 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5030 uItem
.fState
|= MF_USECHECKBITMAPS
;
5032 return NtUserMenuItemInfo(hMenu
, uPosition
,
5033 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
5046 LPCMENUITEMINFOA lpmii
)
5048 MENUITEMINFOW MenuItemInfoW
;
5049 UNICODE_STRING UnicodeString
;
5051 ULONG Result
= FALSE
;
5053 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5055 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5057 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5058 MenuItemInfoW
.hbmpItem
= NULL
;
5061 * MIIM_STRING == good
5062 * MIIM_TYPE & MFT_STRING == good
5063 * MIIM_STRING & MFT_STRING == good
5064 * MIIM_STRING & MFT_OWNERSRAW == good
5066 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5067 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5068 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5069 && MenuItemInfoW
.dwTypeData
!= NULL
)
5071 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5072 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5073 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5074 if (!NT_SUCCESS (Status
))
5076 SetLastError (RtlNtStatusToDosError(Status
));
5079 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5080 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5084 UnicodeString
.Buffer
= NULL
;
5087 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5088 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5090 if (UnicodeString
.Buffer
!= NULL
)
5092 RtlFreeUnicodeString(&UnicodeString
);
5108 LPCMENUITEMINFOW lpmii
)
5110 MENUITEMINFOW MenuItemInfoW
;
5113 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5115 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5117 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5118 MenuItemInfoW
.hbmpItem
= NULL
;
5121 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5122 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5123 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5124 && MenuItemInfoW
.dwTypeData
!= NULL
)
5126 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5128 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5129 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5145 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5150 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5153 return NtUserSetSystemMenu(hwnd
, hMenu
);
5157 // Example for the Win32/User32 rewrite.
5158 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5172 return NtUserTrackPopupMenuEx( Menu
,
5177 NULL
); // LPTPMPARAMS is null
5186 GetMenuContextHelpId(HMENU hmenu
)
5189 mi
.cbSize
= sizeof(ROSMENUINFO
);
5190 mi
.fMask
= MIM_HELPID
;
5192 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5194 return mi
.dwContextHelpID
;
5215 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5218 Result
= (ULONG_PTR
)lResult
;
5223 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5243 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5246 Result
= (ULONG_PTR
)lResult
;
5251 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5262 LPCWSTR lpszNewItem
,
5267 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5268 for MF_DELETE. We should check the parameters for all others
5269 MF_* actions also (anybody got a doc on ChangeMenu?).
5272 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5275 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5278 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5281 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5284 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5285 flags
&~ MF_REMOVE
);
5287 default : /* MF_INSERT */
5288 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5305 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5306 for MF_DELETE. We should check the parameters for all others
5307 MF_* actions also (anybody got a doc on ChangeMenu?).
5310 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5313 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5316 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5319 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5322 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5323 flags
&~ MF_REMOVE
);
5325 default : /* MF_INSERT */
5326 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);