3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS user32.dll
5 * FILE: user32/windows/menu.c
8 * PROGRAMMERS: Casper S. Hornstrup
12 /* INCLUDES ******************************************************************/
15 #include <wine/debug.h>
17 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
19 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
21 /* internal popup menu window messages */
23 #define MM_SETMENUHANDLE (WM_USER + 0)
24 #define MM_GETMENUHANDLE (WM_USER + 1)
26 /* internal flags for menu tracking */
28 #define TF_ENDMENU 0x10000
29 #define TF_SUSPENDPOPUP 0x20000
30 #define TF_SKIPREMOVE 0x40000
35 /* Internal MenuTrackMenu() flags */
36 #define TPM_INTERNAL 0xF0000000
37 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
38 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
39 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
42 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
44 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
46 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
47 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
48 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
50 #define IS_SYSTEM_MENU(MenuInfo) \
51 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
53 #define IS_SYSTEM_POPUP(MenuInfo) \
54 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
56 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
58 /* Use global popup window because there's no way 2 menus can
59 * be tracked at the same time. */
62 /* Flag set by EndMenu() to force an exit from menu tracking */
63 static BOOL fEndMenu
= FALSE
;
65 #define MENU_ITEM_HBMP_SPACE (5)
66 #define MENU_BAR_ITEMS_SPACE (12)
67 #define SEPARATOR_HEIGHT (5)
68 #define MENU_TAB_SPACE (8)
70 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
71 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
72 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
73 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
78 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
79 HMENU TopMenu
; /* initial menu */
80 HWND OwnerWnd
; /* where notifications are sent */
85 /*********************************************************************
86 * PopupMenu class descriptor
88 const struct builtin_class_descr POPUPMENU_builtin_class
=
90 POPUPMENU_CLASS_ATOMW
, /* name */
91 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
92 (WNDPROC
) NULL
, /* FIXME - procA */
93 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
94 sizeof(MENUINFO
*), /* extra */
95 (LPCWSTR
) IDC_ARROW
, /* cursor */
96 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
100 #define GET_WORD(ptr) (*(WORD *)(ptr))
103 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
106 HFONT hMenuFont
= NULL
;
107 HFONT hMenuFontBold
= NULL
;
109 /* Dimension of the menu bitmaps */
110 static HBITMAP BmpSysMenu
= NULL
;
112 static SIZE MenuCharSize
;
114 /***********************************************************************
117 * Get full information about menu
120 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
122 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
123 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
125 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
128 /***********************************************************************
131 * Set full information about menu
134 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
136 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
137 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
139 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
142 /***********************************************************************
143 * MenuInitRosMenuItemInfo
145 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
148 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
150 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
151 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
154 /***********************************************************************
155 * MenuGetRosMenuItemInfo
157 * Get full information about a menu item
160 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
162 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
164 if (ItemInfo
->dwTypeData
!= NULL
)
166 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
170 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
171 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
172 ItemInfo
->dwTypeData
= NULL
;
174 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
180 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
183 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
184 ItemInfo
->cch
* sizeof(WCHAR
));
185 if (NULL
== ItemInfo
->dwTypeData
)
190 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
195 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
197 ItemInfo
->fMask
= Save_Mask
;
201 /***********************************************************************
202 * MenuSetRosMenuItemInfo
204 * Set selected information about a menu item, need to set the mask bits.
207 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
211 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
212 ItemInfo
->dwTypeData
!= NULL
)
214 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
216 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
221 /***********************************************************************
222 * MenuCleanupRosMenuItemInfo
224 * Cleanup after use of MenuGet/SetRosMenuItemInfo
227 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
229 if (ItemInfo
->dwTypeData
!= NULL
)
231 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
232 ItemInfo
->dwTypeData
= NULL
;
236 /***********************************************************************
237 * MenuGetAllRosMenuItemInfo
239 * Get full information about all menu items
242 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
246 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
247 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
251 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
252 if (NULL
== *ItemInfo
)
257 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
260 /***********************************************************************
261 * MenuCleanupAllRosMenuItemInfo
263 * Cleanup after use of MenuGetAllRosMenuItemInfo
266 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
268 HeapFree(GetProcessHeap(), 0, ItemInfo
);
272 /***********************************************************************
275 * Load the arrow bitmap. We can't do this from MenuInit since user32
276 * can also be used (and thus initialized) from text-mode.
279 MenuLoadBitmaps(VOID
)
281 /* Load system buttons bitmaps */
282 if (NULL
== BmpSysMenu
)
284 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
288 /***********************************************************************
291 * Draws popup magic glyphs (can be found in system menu).
294 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
297 HFONT hFont
, hOldFont
;
303 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
306 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
309 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
312 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
316 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
319 ZeroMemory(&lf
, sizeof(LOGFONTW
));
320 InflateRect(r
, -2, -2);
321 lf
.lfHeight
= r
->bottom
- r
->top
;
323 lf
.lfWeight
= FW_NORMAL
;
324 lf
.lfCharSet
= DEFAULT_CHARSET
;
325 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
326 hFont
= CreateFontIndirect(&lf
);
327 /* save font and text color */
328 hOldFont
= SelectObject(dc
, hFont
);
329 clrsave
= GetTextColor(dc
);
330 bkmode
= GetBkMode(dc
);
331 /* set color and drawing mode */
332 SetBkMode(dc
, TRANSPARENT
);
338 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
339 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
342 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
343 /* draw selected symbol */
344 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
345 /* restore previous settings */
346 SetTextColor(dc
, clrsave
);
347 SelectObject(dc
, hOldFont
);
348 SetBkMode(dc
, bkmode
);
352 /***********************************************************************
355 * Find the menu item selected by a key press.
356 * Return item id, -1 if none, -2 if we should close the menu.
358 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
359 WCHAR Key
, BOOL ForceMenuChar
)
361 ROSMENUINFO SysMenuInfo
;
362 PROSMENUITEMINFO Items
, ItemInfo
;
366 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
368 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
370 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
372 MenuInfo
= &SysMenuInfo
;
380 if (NULL
!= MenuInfo
)
382 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
390 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
392 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
394 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
397 p
= strchrW(p
+ 2, '&');
399 while (NULL
!= p
&& L
'&' == p
[1]);
400 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
408 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
409 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
410 if (2 == HIWORD(MenuChar
))
412 return LOWORD(MenuChar
);
414 if (1 == HIWORD(MenuChar
))
423 /***********************************************************************
424 * MenuGetBitmapItemSize
426 * Get the size of a bitmap item.
428 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
,
432 HBITMAP bmp
= lpitem
->hbmpItem
;
434 size
->cx
= size
->cy
= 0;
436 /* check if there is a magic menu item associated with this item */
437 if (IS_MAGIC_BITMAP(bmp
))
439 switch((INT_PTR
) bmp
)
441 case (INT_PTR
)HBMMENU_CALLBACK
:
443 MEASUREITEMSTRUCT measItem
;
444 measItem
.CtlType
= ODT_MENU
;
446 measItem
.itemID
= lpitem
->wID
;
447 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
448 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
449 measItem
.itemData
= lpitem
->dwItemData
;
450 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
451 size
->cx
= measItem
.itemWidth
;
452 size
->cy
= measItem
.itemHeight
;
457 case (INT_PTR
) HBMMENU_SYSTEM
:
458 if (0 != lpitem
->dwItemData
)
460 bmp
= (HBITMAP
) lpitem
->dwItemData
;
464 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
465 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
466 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
467 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
468 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
469 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
470 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
471 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
472 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
473 /* FIXME: Why we need to subtract these magic values? */
474 /* to make them smaller than the menu bar? */
475 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
476 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
481 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
483 size
->cx
= bm
.bmWidth
;
484 size
->cy
= bm
.bmHeight
;
488 /***********************************************************************
491 * Draw a bitmap item.
493 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
494 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
500 int w
= rect
->right
- rect
->left
;
501 int h
= rect
->bottom
- rect
->top
;
504 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
507 /* Check if there is a magic menu item associated with this item */
508 if (IS_MAGIC_BITMAP(hbmToDraw
))
514 switch ((INT_PTR
)hbmToDraw
)
516 case (INT_PTR
)HBMMENU_SYSTEM
:
517 if (lpitem
->dwTypeData
)
519 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
520 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
524 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
526 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
527 /* only use right half of the bitmap */
528 bmp_xoffset
= bm
.bmWidth
/ 2;
529 bm
.bmWidth
-= bmp_xoffset
;
532 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
533 flags
= DFCS_CAPTIONRESTORE
;
535 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
537 flags
= DFCS_CAPTIONMIN
;
539 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
541 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
543 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
544 flags
= DFCS_CAPTIONCLOSE
;
546 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
547 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
549 case (INT_PTR
)HBMMENU_CALLBACK
:
551 DRAWITEMSTRUCT drawItem
;
553 drawItem
.CtlType
= ODT_MENU
;
555 drawItem
.itemID
= lpitem
->wID
;
556 drawItem
.itemAction
= odaction
;
557 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
558 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
559 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
560 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
561 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
562 drawItem
.hwndItem
= (HWND
)hmenu
;
564 drawItem
.rcItem
= *rect
;
565 drawItem
.itemData
= lpitem
->dwItemData
;
566 /* some applications make this assumption on the DC's origin */
567 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
568 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
569 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
570 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
575 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
576 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
577 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
578 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
579 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
582 InflateRect(&r
, -1, -1);
583 if (0 != (lpitem
->fState
& MF_HILITE
))
585 flags
|= DFCS_PUSHED
;
587 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
591 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
594 hdcMem
= CreateCompatibleDC( hdc
);
595 SelectObject( hdcMem
, bmp
);
597 /* handle fontsize > bitmap_height */
598 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
600 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
601 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
602 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
603 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
607 /***********************************************************************
610 * Calculate the size of the menu item and store it in lpitem->rect.
612 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
613 INT orgX
, INT orgY
, BOOL menuBar
)
616 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
619 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
621 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
623 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
625 if (lpitem
->fType
& MF_OWNERDRAW
)
627 MEASUREITEMSTRUCT mis
;
628 mis
.CtlType
= ODT_MENU
;
630 mis
.itemID
= lpitem
->wID
;
631 mis
.itemData
= lpitem
->dwItemData
;
632 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
634 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
635 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
636 * width of a menufont character to the width of an owner-drawn menu.
638 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
641 /* under at least win95 you seem to be given a standard
642 height for the menu and the height value is ignored */
643 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
645 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
647 TRACE("id=%04lx size=%dx%d\n",
648 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
652 if (lpitem
->fType
& MF_SEPARATOR
)
654 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
656 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
662 if (lpitem
->hbmpItem
)
667 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
668 /* Keep the size of the bitmap in callback mode to be able
669 * to draw it correctly */
670 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
671 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
672 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
674 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
675 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
677 MenuSetRosMenuInfo(MenuInfo
);
678 itemheight
= size
.cy
+ 2;
680 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
681 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
682 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
683 lpitem
->XTab
= lpitem
->Rect
.right
;
684 lpitem
->Rect
.right
+= check_bitmap_width
;
685 } else /* hbmpItem & MenuBar */ {
686 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
687 lpitem
->Rect
.right
+= size
.cx
;
688 if( lpitem
->Text
) lpitem
->Rect
.right
+= 2;
689 itemheight
= size
.cy
;
691 /* Special case: Minimize button doesn't have a space behind it. */
692 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
693 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
694 lpitem
->Rect
.right
-= 1;
698 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
699 lpitem
->Rect
.right
+= check_bitmap_width
;
700 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
701 lpitem
->XTab
= lpitem
->Rect
.right
;
702 lpitem
->Rect
.right
+= check_bitmap_width
;
705 /* it must be a text item - unless it's the system menu */
706 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Text
) {
707 HFONT hfontOld
= NULL
;
708 RECT rc
= lpitem
->Rect
;
709 LONG txtheight
, txtwidth
;
711 if ( lpitem
->fState
& MFS_DEFAULT
) {
712 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
715 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
716 DT_SINGLELINE
|DT_CALCRECT
);
717 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
718 itemheight
= max( max( itemheight
, txtheight
),
719 GetSystemMetrics( SM_CYMENU
) - 1);
720 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
722 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
725 int n
= (int)( p
- lpitem
->dwTypeData
);
726 /* Item contains a tab (only meaningful in popup menus) */
727 /* get text size before the tab */
728 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
729 DT_SINGLELINE
|DT_CALCRECT
);
730 txtwidth
= rc
.right
- rc
.left
;
731 p
+= 1; /* advance past the Tab */
732 /* get text size after the tab */
733 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
734 DT_SINGLELINE
|DT_CALCRECT
);
735 lpitem
->XTab
+= txtwidth
;
736 txtheight
= max( txtheight
, tmpheight
);
737 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
738 tmprc
.right
- tmprc
.left
; /* space for the short cut */
740 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
741 DT_SINGLELINE
|DT_CALCRECT
);
742 txtwidth
= rc
.right
- rc
.left
;
743 lpitem
->XTab
+= txtwidth
;
745 lpitem
->Rect
.right
+= 2 + txtwidth
;
746 itemheight
= max( itemheight
,
747 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
749 if (hfontOld
) SelectObject (hdc
, hfontOld
);
750 } else if( menuBar
) {
751 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
753 lpitem
->Rect
.bottom
+= itemheight
;
754 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
757 /***********************************************************************
758 * MenuPopupMenuCalcSize
760 * Calculate the size of a popup menu.
762 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
764 ROSMENUITEMINFO lpitem
;
767 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
769 MenuInfo
->Width
= MenuInfo
->Height
= 0;
770 if (MenuInfo
->MenuItemCount
== 0)
772 MenuSetRosMenuInfo(MenuInfo
);
777 SelectObject( hdc
, hMenuFont
);
782 MenuInfo
->maxBmpSize
.cx
= 0;
783 MenuInfo
->maxBmpSize
.cy
= 0;
785 MenuInitRosMenuItemInfo(&lpitem
);
786 while (start
< MenuInfo
->MenuItemCount
)
791 maxTab
= maxTabWidth
= 0;
793 /* Parse items until column break or end of menu */
794 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
796 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
798 MenuCleanupRosMenuItemInfo(&lpitem
);
799 MenuSetRosMenuInfo(MenuInfo
);
803 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
805 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
806 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
808 MenuCleanupRosMenuItemInfo(&lpitem
);
809 MenuSetRosMenuInfo(MenuInfo
);
812 // Not sure here,, The patch from wine removes this.
813 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
817 maxX
= max(maxX
, lpitem
.Rect
.right
);
818 orgY
= lpitem
.Rect
.bottom
;
819 if ((lpitem
.Text
) && lpitem
.XTab
)
821 maxTab
= max( maxTab
, lpitem
.XTab
);
822 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.XTab
);
826 /* Finish the column (set all items to the largest width found) */
827 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
830 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
832 lpitem
.Rect
.right
= maxX
;
833 if ((lpitem
.Text
) && 0 != lpitem
.XTab
)
835 lpitem
.XTab
= maxTab
;
837 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
841 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
844 MenuInfo
->Width
= maxX
;
846 /* space for 3d border */
847 MenuInfo
->Height
+= 2;
848 MenuInfo
->Width
+= 2;
850 MenuCleanupRosMenuItemInfo(&lpitem
);
851 MenuSetRosMenuInfo(MenuInfo
);
855 /***********************************************************************
856 * MenuMenuBarCalcSize
858 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
859 * height is off by 1 pixel which causes lengthy window relocations when
860 * active document window is maximized/restored.
862 * Calculate the size of the menu bar.
864 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
865 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
867 ROSMENUITEMINFO ItemInfo
;
868 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
870 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
871 if (MenuInfo
->MenuItemCount
== 0) return;
872 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
873 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
874 MenuInfo
->Height
= 0;
875 maxY
= lprect
->top
+ 1;
879 MenuInfo
->maxBmpSize
.cx
= 0;
880 MenuInfo
->maxBmpSize
.cy
= 0;
882 MenuInitRosMenuItemInfo(&ItemInfo
);
883 while (start
< MenuInfo
->MenuItemCount
)
885 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
887 MenuCleanupRosMenuItemInfo(&ItemInfo
);
893 /* Parse items until line break or end of menu */
894 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
896 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
898 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
900 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
901 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
902 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
904 MenuCleanupRosMenuItemInfo(&ItemInfo
);
908 if (ItemInfo
.Rect
.right
> lprect
->right
)
910 if (i
!= start
) break;
911 else ItemInfo
.Rect
.right
= lprect
->right
;
913 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
914 orgX
= ItemInfo
.Rect
.right
;
915 if (i
+ 1 < MenuInfo
->MenuItemCount
)
917 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
919 MenuCleanupRosMenuItemInfo(&ItemInfo
);
925 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
926 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
928 /* Finish the line (set all items to the largest height found) */
931 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
933 ItemInfo
.Rect
.bottom
= maxY
;
934 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
939 start
= i
; /* This works! */
943 lprect
->bottom
= maxY
;
944 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
945 MenuSetRosMenuInfo(MenuInfo
);
949 /* Flush right all items between the MF_RIGHTJUSTIFY and */
950 /* the last item (if several lines, only move the last line) */
951 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
953 MenuCleanupRosMenuItemInfo(&ItemInfo
);
956 orgY
= ItemInfo
.Rect
.top
;
957 orgX
= lprect
->right
;
958 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
964 if (ItemInfo
.Rect
.top
!= orgY
)
966 break; /* Other line */
968 if (orgX
<= ItemInfo
.Rect
.right
)
970 break; /* Too far right already */
972 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
973 ItemInfo
.Rect
.right
= orgX
;
974 orgX
= ItemInfo
.Rect
.left
;
975 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
976 if (helpPos
+ 1 <= i
&&
977 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
979 MenuCleanupRosMenuItemInfo(&ItemInfo
);
985 MenuCleanupRosMenuItemInfo(&ItemInfo
);
988 /***********************************************************************
991 * Draw a single menu item.
993 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
994 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
998 BOOL flat_menu
= FALSE
;
1000 PWND Wnd
= ValidateHwnd(hWnd
);
1005 if (lpitem
->fType
& MF_SYSMENU
)
1007 if ( (Wnd
->style
& WS_MINIMIZE
))
1009 UserGetInsideRectNC(Wnd
, &rect
);
1010 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1011 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1016 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1017 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1021 if (lpitem
->fState
& MF_HILITE
)
1023 if(menuBar
&& !flat_menu
) {
1024 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1025 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1027 if (lpitem
->fState
& MF_GRAYED
)
1028 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1030 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1031 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1036 if (lpitem
->fState
& MF_GRAYED
)
1037 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1039 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1040 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1043 rect
= lpitem
->Rect
;
1045 if (lpitem
->fType
& MF_OWNERDRAW
)
1048 ** Experimentation under Windows reveals that an owner-drawn
1049 ** menu is given the rectangle which includes the space it requested
1050 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1051 ** and a popup-menu arrow. This is the value of lpitem->rect.
1052 ** Windows will leave all drawing to the application except for
1053 ** the popup-menu arrow. Windows always draws that itself, after
1054 ** the menu owner has finished drawing.
1058 dis
.CtlType
= ODT_MENU
;
1060 dis
.itemID
= lpitem
->wID
;
1061 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1063 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1064 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1065 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1066 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1067 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1070 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1071 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1072 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1073 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1075 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1076 /* Draw the popup-menu arrow */
1077 if (lpitem
->fType
& MF_POPUP
)
1080 CopyRect(&rectTemp
, &rect
);
1081 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1082 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1087 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1089 if (lpitem
->fState
& MF_HILITE
)
1093 InflateRect (&rect
, -1, -1);
1094 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1095 InflateRect (&rect
, 1, 1);
1096 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1101 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1103 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1107 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1109 SetBkMode( hdc
, TRANSPARENT
);
1111 /* vertical separator */
1112 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1119 rc
.bottom
= Height
- 3;
1122 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1123 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1124 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1125 LineTo( hdc
, rc
.left
, rc
.bottom
);
1126 SelectObject( hdc
, oldPen
);
1129 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1132 /* horizontal separator */
1133 if (lpitem
->fType
& MF_SEPARATOR
)
1140 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1143 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1144 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1145 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1146 LineTo( hdc
, rc
.right
, rc
.top
);
1147 SelectObject( hdc
, oldPen
);
1150 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1155 /* helper lines for debugging */
1156 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1157 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1158 SelectObject(hdc
, GetStockObject(DC_PEN
));
1159 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1160 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1161 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1167 INT y
= rect
.top
+ rect
.bottom
;
1169 int checked
= FALSE
;
1170 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1171 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1172 /* Draw the check mark
1175 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1177 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1178 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1179 lpitem
->hbmpUnchecked
;
1180 if (bm
) /* we have a custom bitmap */
1182 HDC hdcMem
= CreateCompatibleDC( hdc
);
1184 SelectObject( hdcMem
, bm
);
1185 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1186 check_bitmap_width
, check_bitmap_height
,
1187 hdcMem
, 0, 0, SRCCOPY
);
1191 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1194 CopyRect(&r
, &rect
);
1195 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1196 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1197 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1198 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1202 if ( lpitem
->hbmpItem
)
1205 CopyRect(&bmpRect
, &rect
);
1206 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1207 bmpRect
.left
+= check_bitmap_width
+ 2;
1208 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1210 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1211 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1214 /* Draw the popup-menu arrow */
1215 if (lpitem
->fType
& MF_POPUP
)
1218 CopyRect(&rectTemp
, &rect
);
1219 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1220 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1223 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1224 rect
.left
+= check_bitmap_width
;
1225 rect
.right
-= check_bitmap_width
;
1227 else if( lpitem
->hbmpItem
)
1228 { /* Draw the bitmap */
1229 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1232 /* process text if present */
1238 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1239 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1241 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1242 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1244 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1246 if ( lpitem
->fState
& MFS_DEFAULT
)
1248 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1252 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1253 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1256 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1259 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1260 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1264 if(lpitem
->fState
& MF_GRAYED
)
1266 if (!(lpitem
->fState
& MF_HILITE
) )
1268 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1269 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1270 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1271 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1273 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1276 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1278 /* paint the shortcut text */
1279 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1281 if (L
'\t' == Text
[i
])
1283 rect
.left
= lpitem
->XTab
;
1284 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1288 rect
.right
= lpitem
->XTab
;
1289 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1292 if (lpitem
->fState
& MF_GRAYED
)
1294 if (!(lpitem
->fState
& MF_HILITE
) )
1296 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1297 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1298 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1299 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1301 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1303 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1307 SelectObject (hdc
, hfontOld
);
1311 /***********************************************************************
1314 * Paint a popup menu.
1316 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1318 HBRUSH hPrevBrush
= 0;
1321 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1323 GetClientRect( hwnd
, &rect
);
1325 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1326 && (SelectObject( hdc
, hMenuFont
)))
1330 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1332 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1335 BOOL flat_menu
= FALSE
;
1336 ROSMENUINFO MenuInfo
;
1337 ROSMENUITEMINFO ItemInfo
;
1339 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1341 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1343 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1345 /* draw menu items */
1346 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1350 MenuInitRosMenuItemInfo(&ItemInfo
);
1352 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1354 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1356 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1357 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1361 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1365 SelectObject( hdc
, hPrevBrush
);
1370 /***********************************************************************
1373 * Paint a menu bar. Returns the height of the menu bar.
1374 * called from [windows/nonclient.c]
1376 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1381 HMENU hMenu
= GetMenu(hwnd
);
1383 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1385 return GetSystemMetrics(SM_CYMENU
);
1390 hfontOld
= SelectObject(hDC
, hMenuFont
);
1392 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1394 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1396 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1397 return lppop
.Height
;
1400 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1403 /***********************************************************************
1406 * Display a popup menu.
1408 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1409 INT x
, INT y
, INT xanchor
, INT yanchor
)
1411 ROSMENUINFO MenuInfo
;
1412 ROSMENUITEMINFO ItemInfo
;
1418 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1419 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1421 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1422 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1424 MenuInitRosMenuItemInfo(&ItemInfo
);
1425 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1427 ItemInfo
.fMask
|= MIIM_STATE
;
1428 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1429 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1431 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1432 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1435 /* store the owner for DrawItem */
1436 MenuInfo
.WndOwner
= hwndOwner
;
1437 MenuSetRosMenuInfo(&MenuInfo
);
1439 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1441 /* adjust popup menu pos so that it fits within the desktop */
1443 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1444 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1446 /* FIXME: should use item rect */
1449 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1450 info
.cbSize
= sizeof(info
);
1451 GetMonitorInfoW( monitor
, &info
);
1453 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1454 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1456 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1457 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1459 if( x
+ width
> info
.rcWork
.right
)
1461 if( xanchor
&& x
>= width
- xanchor
)
1462 x
-= width
- xanchor
;
1464 if( x
+ width
> info
.rcWork
.right
)
1465 x
= info
.rcWork
.right
- width
;
1467 if( x
< info
.rcWork
.left
) x
= info
.rcWork
.left
;
1469 if( y
+ height
> info
.rcWork
.bottom
)
1471 if( yanchor
&& y
>= height
+ yanchor
)
1472 y
-= height
+ yanchor
;
1474 if( y
+ height
> info
.rcWork
.bottom
)
1475 y
= info
.rcWork
.bottom
- height
;
1477 if( y
< info
.rcWork
.top
) y
= info
.rcWork
.top
;
1479 /* NOTE: In Windows, top menu popup is not owned. */
1480 MenuInfo
.Wnd
= CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW
, NULL
,
1481 WS_POPUP
, x
, y
, width
, height
,
1482 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1483 (LPVOID
) MenuInfo
.Self
);
1484 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1486 TopPopup
= MenuInfo
.Wnd
;
1489 /* Display the window */
1491 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1492 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1493 UpdateWindow( MenuInfo
.Wnd
);
1498 PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1500 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1506 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1507 SetWindowLongPtrA(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1511 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1512 return MA_NOACTIVATE
;
1517 BeginPaint(Wnd
, &ps
);
1518 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1523 case WM_PRINTCLIENT
:
1525 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1526 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1534 /* zero out global pointer in case resident popup window was destroyed. */
1535 if (Wnd
== TopPopup
)
1544 if (0 == GetWindowLongPtrA(Wnd
, 0))
1546 OutputDebugStringA("no menu to display\n");
1551 SetWindowLongPtrA(Wnd
, 0, 0);
1555 case MM_SETMENUHANDLE
:
1556 SetWindowLongPtrA(Wnd
, 0, wParam
);
1559 case MM_GETMENUHANDLE
:
1561 return GetWindowLongPtrA(Wnd
, 0);
1564 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1570 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1572 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1578 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1579 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1583 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1584 return MA_NOACTIVATE
;
1589 BeginPaint(Wnd
, &ps
);
1590 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1595 case WM_PRINTCLIENT
:
1597 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1598 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1606 /* zero out global pointer in case resident popup window was destroyed. */
1607 if (Wnd
== TopPopup
)
1616 if (0 == GetWindowLongPtrW(Wnd
, 0))
1618 OutputDebugStringA("no menu to display\n");
1623 SetWindowLongPtrW(Wnd
, 0, 0);
1627 case MM_SETMENUHANDLE
:
1628 SetWindowLongPtrW(Wnd
, 0, wParam
);
1631 case MM_GETMENUHANDLE
:
1633 return GetWindowLongPtrW(Wnd
, 0);
1636 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1642 /**********************************************************************
1643 * MENUEX_ParseResource
1645 * Parse an extended menu resource and add items to the menu.
1646 * Return a pointer to the end of the resource.
1648 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
1650 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1658 mii
.cbSize
= sizeof(mii
);
1659 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
1660 mii
.fType
= GET_DWORD(res
);
1661 res
+= sizeof(DWORD
);
1662 mii
.fState
= GET_DWORD(res
);
1663 res
+= sizeof(DWORD
);
1664 mii
.wID
= GET_DWORD(res
);
1665 res
+= sizeof(DWORD
);
1666 resinfo
= GET_WORD(res
);
1667 res
+= sizeof(WORD
);
1668 /* Align the text on a word boundary. */
1669 res
+= (~((int)res
- 1)) & 1;
1670 mii
.dwTypeData
= (LPWSTR
) res
;
1671 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1672 /* Align the following fields on a dword boundary. */
1673 res
+= (~((int)res
- 1)) & 3;
1675 if (resinfo
& 1) /* Pop-up? */
1677 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1678 res
+= sizeof(DWORD
);
1679 mii
.hSubMenu
= CreatePopupMenu();
1682 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1684 DestroyMenu(mii
.hSubMenu
);
1687 mii
.fMask
|= MIIM_SUBMENU
;
1688 mii
.fType
|= MF_POPUP
;
1689 mii
.wID
= (UINT
) mii
.hSubMenu
;
1691 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1693 mii
.fType
|= MF_SEPARATOR
;
1695 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1697 while (!(resinfo
& MF_END
));
1702 /**********************************************************************
1703 * MENU_ParseResource
1705 * Parse a standard menu resource and add items to the menu.
1706 * Return a pointer to the end of the resource.
1708 * NOTE: flags is equivalent to the mtOption field
1710 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1719 flags
= GET_WORD(res
);
1721 /* remove MF_END flag before passing it to AppendMenu()! */
1722 end
= (flags
& MF_END
);
1723 if(end
) flags
^= MF_END
;
1725 res
+= sizeof(WORD
);
1726 if(!(flags
& MF_POPUP
))
1729 res
+= sizeof(WORD
);
1733 res
+= strlen(str
) + 1;
1735 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1736 if (flags
& MF_POPUP
)
1738 hSubMenu
= CreatePopupMenu();
1739 if(!hSubMenu
) return NULL
;
1740 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1743 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1745 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1747 else /* Not a popup */
1752 flags
= MF_SEPARATOR
;
1756 if (*(LPCWSTR
)str
== 0)
1757 flags
= MF_SEPARATOR
;
1760 if (flags
& MF_SEPARATOR
)
1762 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1763 flags
|= MF_GRAYED
| MF_DISABLED
;
1767 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1769 AppendMenuW(hMenu
, flags
, id
,
1770 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1779 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1781 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
1782 LRESULT Result
= (LRESULT
)hmenu
;
1783 MENUINFO menuinfo
= {0};
1784 MENUITEMINFOW info
= {0};
1786 // removing space for checkboxes from menu
1787 menuinfo
.cbSize
= sizeof(menuinfo
);
1788 menuinfo
.fMask
= MIM_STYLE
;
1789 GetMenuInfo(hmenu
, &menuinfo
);
1790 menuinfo
.dwStyle
|= MNS_NOCHECK
;
1791 SetMenuInfo(hmenu
, &menuinfo
);
1793 // adding bitmaps to menu items
1794 info
.cbSize
= sizeof(info
);
1795 info
.fMask
|= MIIM_BITMAP
;
1796 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
1797 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
1798 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
1799 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
1800 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
1801 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
1802 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
1803 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
1805 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1812 NONCLIENTMETRICSW ncm
;
1814 /* get the menu font */
1815 if(!hMenuFont
|| !hMenuFontBold
)
1817 ncm
.cbSize
= sizeof(ncm
);
1818 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1820 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1824 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1825 if(hMenuFont
== NULL
)
1827 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1831 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1832 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1833 if(hMenuFontBold
== NULL
)
1835 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1836 DeleteObject(hMenuFont
);
1850 DeleteObject(hMenuFont
);
1856 DeleteObject(hMenuFontBold
);
1857 hMenuFontBold
= NULL
;
1861 /***********************************************************************
1862 * DrawMenuBarTemp (USER32.@)
1866 * called by W98SE desk.cpl Control Panel Applet
1868 * Not 100% sure about the param names, but close.
1873 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1875 ROSMENUINFO MenuInfo
;
1876 ROSMENUITEMINFO ItemInfo
;
1878 HFONT FontOld
= NULL
;
1879 BOOL flat_menu
= FALSE
;
1881 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1885 Menu
= GetMenu(Wnd
);
1893 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1895 return GetSystemMetrics(SM_CYMENU
);
1898 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1900 FontOld
= SelectObject(DC
, Font
);
1902 if (0 == MenuInfo
.Height
)
1904 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1907 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1909 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
1911 SelectObject(DC
, GetStockObject(DC_PEN
));
1912 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
1913 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1914 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1916 if (0 == MenuInfo
.MenuItemCount
)
1918 SelectObject(DC
, FontOld
);
1919 return GetSystemMetrics(SM_CYMENU
);
1922 MenuInitRosMenuItemInfo(&ItemInfo
);
1923 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1925 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1927 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1928 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1931 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1933 SelectObject(DC
, FontOld
);
1935 return MenuInfo
.Height
;
1938 /***********************************************************************
1941 static BOOL FASTCALL
1942 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1944 TRACE("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1948 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1949 if (0 == (Flags
& TPM_NONOTIFY
))
1951 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1954 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1956 if (0 == (Flags
& TPM_NONOTIFY
))
1958 ROSMENUINFO MenuInfo
;
1960 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1962 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
1964 if (0 == MenuInfo
.Height
)
1966 /* app changed/recreated menu bar entries in WM_INITMENU
1967 Recalculate menu sizes else clicks will not work */
1968 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1969 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1972 /* This makes the menus of applications built with Delphi work.
1973 * It also enables menus to be displayed in more than one window,
1974 * but there are some bugs left that need to be fixed in this case.
1976 if(MenuInfo
.Self
== Menu
)
1979 MenuSetRosMenuInfo(&MenuInfo
);
1986 /***********************************************************************
1989 * Find a Sub menu. Return the position of the submenu, and modifies
1990 * *hmenu in case it is found in another sub-menu.
1991 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
1993 static UINT FASTCALL
1994 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
1996 ROSMENUINFO MenuInfo
;
1997 ROSMENUITEMINFO ItemInfo
;
2002 if ((HMENU
) 0xffff == *Menu
2003 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
2005 return NO_SELECTED_ITEM
;
2008 MenuInitRosMenuItemInfo(&ItemInfo
);
2009 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2011 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2013 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2014 return NO_SELECTED_ITEM
;
2016 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2020 if (ItemInfo
.hSubMenu
== SubTarget
)
2022 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2025 SubMenu
= ItemInfo
.hSubMenu
;
2026 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
2027 if (NO_SELECTED_ITEM
!= Pos
)
2033 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2035 return NO_SELECTED_ITEM
;
2038 /***********************************************************************
2041 static void FASTCALL
2042 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
2043 BOOL SendMenuSelect
, HMENU TopMenu
)
2046 ROSMENUITEMINFO ItemInfo
;
2047 ROSMENUINFO TopMenuInfo
;
2050 TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
2052 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
2057 if (MenuInfo
->FocusedItem
== Index
)
2062 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2064 Dc
= GetDC(MenuInfo
->Wnd
);
2068 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2071 if (NULL
== TopPopup
)
2073 TopPopup
= MenuInfo
->Wnd
;
2076 SelectObject(Dc
, hMenuFont
);
2077 MenuInitRosMenuItemInfo(&ItemInfo
);
2078 /* Clear previous highlighted item */
2079 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2081 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2083 ItemInfo
.fMask
|= MIIM_STATE
;
2084 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2085 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2087 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
2088 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2092 /* Highlight new item (if any) */
2093 MenuInfo
->FocusedItem
= Index
;
2094 MenuSetRosMenuInfo(MenuInfo
);
2095 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2097 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2099 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2101 ItemInfo
.fMask
|= MIIM_STATE
;
2102 ItemInfo
.fState
|= MF_HILITE
;
2103 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2104 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
2105 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2110 SendMessageW(WndOwner
, WM_MENUSELECT
,
2111 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
2112 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
2113 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
2117 else if (SendMenuSelect
)
2119 if (NULL
!= TopMenu
)
2121 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
2122 if (NO_SELECTED_ITEM
!= Pos
)
2124 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
2125 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
2127 SendMessageW(WndOwner
, WM_MENUSELECT
,
2128 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
2130 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
2136 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2137 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2140 /***********************************************************************
2143 * Moves currently selected item according to the Offset parameter.
2144 * If there is no selection then it should select the last item if
2145 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2147 static void FASTCALL
2148 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2151 ROSMENUITEMINFO ItemInfo
;
2154 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2156 /* Prevent looping */
2157 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
2159 else if (Offset
< -1)
2161 else if (Offset
> 1)
2164 MenuInitRosMenuItemInfo(&ItemInfo
);
2166 OrigPos
= MenuInfo
->FocusedItem
;
2167 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2174 i
= MenuInfo
->FocusedItem
;
2181 /* Clip and wrap around */
2184 i
= MenuInfo
->MenuItemCount
- 1;
2186 else if (i
>= MenuInfo
->MenuItemCount
)
2190 /* If this is a good candidate; */
2191 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2192 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2194 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2195 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2198 } while (i
!= OrigPos
);
2201 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2204 /***********************************************************************
2205 * MenuInitSysMenuPopup
2207 * Grey the appropriate items in System menu.
2210 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2218 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2219 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2220 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2221 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2222 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2223 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2224 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2225 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2226 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2227 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2228 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2230 /* The menu item must keep its state if it's disabled */
2233 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2236 /* Set default menu item */
2237 if(Style
& WS_MINIMIZE
)
2239 DefItem
= SC_RESTORE
;
2243 if(HitTest
== HTCAPTION
)
2245 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2253 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2254 mii
.fMask
|= MIIM_STATE
;
2255 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2256 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2261 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2264 /***********************************************************************
2267 * Display the sub-menu of the selected item of this menu.
2268 * Return the handle of the submenu, or menu if no submenu to display.
2270 static HMENU FASTCALL
2271 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2273 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2275 ROSMENUITEMINFO ItemInfo
;
2276 ROSMENUINFO SubMenuInfo
;
2280 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2282 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2284 return MenuInfo
->Self
;
2287 MenuInitRosMenuItemInfo(&ItemInfo
);
2288 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2290 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2291 return MenuInfo
->Self
;
2293 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2295 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2296 return MenuInfo
->Self
;
2299 /* message must be sent before using item,
2300 because nearly everything may be changed by the application ! */
2302 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2303 if (0 == (Flags
& TPM_NONOTIFY
))
2305 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2306 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2309 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2311 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2312 return MenuInfo
->Self
;
2314 Rect
= ItemInfo
.Rect
;
2316 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2317 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2319 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2321 Dc
= GetDC(MenuInfo
->Wnd
);
2325 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2328 SelectObject(Dc
, hMenuFont
);
2329 ItemInfo
.fMask
|= MIIM_STATE
;
2330 ItemInfo
.fState
|= MF_HILITE
;
2331 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2332 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2333 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2334 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2337 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2338 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2340 ItemInfo
.Rect
= Rect
;
2343 ItemInfo
.fMask
|= MIIM_STATE
;
2344 ItemInfo
.fState
|= MF_MOUSESELECT
;
2345 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2347 if (IS_SYSTEM_MENU(MenuInfo
))
2349 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2350 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2352 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2353 Rect
.top
= Rect
.bottom
;
2354 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2355 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2359 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2360 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2362 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2363 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2364 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2365 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2366 - GetSystemMetrics(SM_CYBORDER
);
2370 Rect
.left
+= ItemInfo
.Rect
.left
;
2371 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2372 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2373 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2377 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2378 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2379 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2381 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2384 Ret
= ItemInfo
.hSubMenu
;
2385 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2390 /***********************************************************************
2393 * Hide the sub-popup menus of this menu.
2395 static void FASTCALL
2396 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2398 ROSMENUINFO SubMenuInfo
;
2399 ROSMENUITEMINFO ItemInfo
;
2401 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2403 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2405 MenuInitRosMenuItemInfo(&ItemInfo
);
2406 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2407 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2408 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2409 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2411 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2414 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2415 ItemInfo
.fMask
|= MIIM_STATE
;
2416 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2417 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2419 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2420 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2421 DestroyWindow(SubMenuInfo
.Wnd
);
2422 SubMenuInfo
.Wnd
= NULL
;
2423 MenuSetRosMenuInfo(&SubMenuInfo
);
2428 /***********************************************************************
2429 * MenuSwitchTracking
2431 * Helper function for menu navigation routines.
2433 static void FASTCALL
2434 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2436 ROSMENUINFO TopMenuInfo
;
2438 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2440 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2441 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2442 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2444 /* both are top level menus (system and menu-bar) */
2445 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2446 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2447 Mt
->TopMenu
= PtMenuInfo
->Self
;
2451 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2454 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2457 /***********************************************************************
2458 * MenuExecFocusedItem
2460 * Execute a menu item (for instance when user pressed Enter).
2461 * Return the wID of the executed item. Otherwise, -1 indicating
2462 * that no menu item was executed, -2 if a popup is shown;
2463 * Have to receive the flags for the TrackPopupMenu options to avoid
2464 * sending unwanted message.
2468 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2470 ROSMENUITEMINFO ItemInfo
;
2473 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2475 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2480 MenuInitRosMenuItemInfo(&ItemInfo
);
2481 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2483 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2487 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2489 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2491 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2492 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2494 /* If TPM_RETURNCMD is set you return the id, but
2495 do not send a message to the owner */
2496 if (0 == (Flags
& TPM_RETURNCMD
))
2498 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2500 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2501 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2505 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2506 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2507 MenuInfo
->FocusedItem
,
2508 (LPARAM
)MenuInfo
->Self
);
2510 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2514 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2520 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2527 /***********************************************************************
2530 * Return TRUE if we can go on with menu tracking.
2532 static BOOL FASTCALL
2533 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2536 ROSMENUINFO MenuInfo
;
2537 ROSMENUITEMINFO Item
;
2539 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2543 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2547 if (IS_SYSTEM_MENU(&MenuInfo
))
2553 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2555 MenuInitRosMenuItemInfo(&Item
);
2556 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2558 MenuCleanupRosMenuItemInfo(&Item
);
2562 if (!(Item
.fType
& MF_SEPARATOR
) &&
2563 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2565 if (MenuInfo
.FocusedItem
!= Index
)
2567 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2570 /* If the popup menu is not already "popped" */
2571 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2573 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2577 MenuCleanupRosMenuItemInfo(&Item
);
2582 /* else the click was on the menu bar, finish the tracking */
2587 /***********************************************************************
2590 * Return the value of MenuExecFocusedItem if
2591 * the selected item was not a popup. Else open the popup.
2592 * A -1 return value indicates that we go on with menu tracking.
2596 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2599 ROSMENUINFO MenuInfo
;
2600 ROSMENUITEMINFO ItemInfo
;
2602 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2607 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2612 if (! IS_SYSTEM_MENU(&MenuInfo
))
2614 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2616 MenuInitRosMenuItemInfo(&ItemInfo
);
2617 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2618 MenuInfo
.FocusedItem
== Id
)
2620 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2622 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2623 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2624 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2626 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2628 /* If we are dealing with the top-level menu */
2629 /* and this is a click on an already "popped" item: */
2630 /* Stop the menu tracking and close the opened submenus */
2631 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2633 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2637 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2638 MenuInfo
.TimeToHide
= TRUE
;
2639 MenuSetRosMenuInfo(&MenuInfo
);
2645 /***********************************************************************
2648 * Walks menu chain trying to find a menu pt maps to.
2650 static HMENU FASTCALL
2651 MenuPtMenu(HMENU Menu
, POINT Pt
)
2653 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2654 ROSMENUINFO MenuInfo
;
2655 ROSMENUITEMINFO ItemInfo
;
2659 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2664 /* try subpopup first (if any) */
2665 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2667 MenuInitRosMenuItemInfo(&ItemInfo
);
2668 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2669 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2670 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2672 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2675 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2679 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2682 /* check the current window (avoiding WM_HITTEST) */
2683 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2684 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2686 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2691 else if (HTSYSMENU
== Ht
)
2693 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2695 else if (HTMENU
== Ht
)
2697 Ret
= GetMenu(MenuInfo
.Wnd
);
2703 /***********************************************************************
2706 * Return TRUE if we can go on with menu tracking.
2708 static BOOL FASTCALL
2709 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2712 ROSMENUINFO MenuInfo
;
2713 ROSMENUITEMINFO ItemInfo
;
2717 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2721 if (IS_SYSTEM_MENU(&MenuInfo
))
2727 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2732 Index
= NO_SELECTED_ITEM
;
2735 if (NO_SELECTED_ITEM
== Index
)
2737 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2738 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2740 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2744 else if (MenuInfo
.FocusedItem
!= Index
)
2746 MenuInitRosMenuItemInfo(&ItemInfo
);
2747 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2748 !(ItemInfo
.fType
& MF_SEPARATOR
))
2750 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2751 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2752 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2754 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2760 /******************************************************************************
2762 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2764 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2767 PROSMENUITEMINFO MenuItems
;
2769 i
= MenuInfo
->FocusedItem
;
2770 if (NO_SELECTED_ITEM
== i
)
2775 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2777 return NO_SELECTED_ITEM
;
2780 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2782 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2788 return NO_SELECTED_ITEM
;
2791 /******************************************************************************
2793 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2795 static UINT FASTCALL
2796 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2799 PROSMENUITEMINFO MenuItems
;
2801 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2803 return NO_SELECTED_ITEM
;
2806 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2808 return NO_SELECTED_ITEM
;
2811 /* Find the start of the column */
2813 for (i
= MenuInfo
->FocusedItem
;
2814 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2822 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2823 return NO_SELECTED_ITEM
;
2826 for (--i
; 0 != i
; --i
)
2828 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2834 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2835 TRACE("ret %d.\n", i
);
2840 /***********************************************************************
2843 * Return the handle of the selected sub-popup menu (if any).
2845 static HMENU FASTCALL
2846 MenuGetSubPopup(HMENU Menu
)
2848 ROSMENUINFO MenuInfo
;
2849 ROSMENUITEMINFO ItemInfo
;
2851 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2852 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2857 MenuInitRosMenuItemInfo(&ItemInfo
);
2858 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2860 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2863 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2865 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2866 return ItemInfo
.hSubMenu
;
2869 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2873 /***********************************************************************
2876 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2878 static LRESULT FASTCALL
2879 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2881 ROSMENUINFO TopMenuInfo
;
2882 ROSMENUINFO MenuInfo
;
2884 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2886 return (LRESULT
) FALSE
;
2889 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2890 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2892 MDINEXTMENU NextMenu
;
2897 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2898 NextMenu
.hmenuNext
= NULL
;
2899 NextMenu
.hwndNext
= NULL
;
2900 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2902 TRACE("%p [%p] -> %p [%p]\n",
2903 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2905 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2907 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2908 NewWnd
= Mt
->OwnerWnd
;
2909 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2911 /* switch to the menu bar */
2913 if (0 != (Style
& WS_CHILD
)
2914 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2921 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2925 Id
= MenuInfo
.MenuItemCount
- 1;
2928 else if (0 != (Style
& WS_SYSMENU
))
2930 /* switch to the system menu */
2931 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2938 else /* application returned a new menu to switch to */
2940 NewMenu
= NextMenu
.hmenuNext
;
2941 NewWnd
= NextMenu
.hwndNext
;
2943 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2945 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2947 if (0 != (Style
& WS_SYSMENU
)
2948 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2950 /* get the real system menu */
2951 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2953 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2955 /* FIXME: Not sure what to do here;
2956 * perhaps try to track NewMenu as a popup? */
2958 WARN(" -- got confused.\n");
2968 if (NewMenu
!= Mt
->TopMenu
)
2970 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2972 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2974 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2978 if (NewWnd
!= Mt
->OwnerWnd
)
2980 Mt
->OwnerWnd
= NewWnd
;
2981 SetCapture(Mt
->OwnerWnd
);
2982 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2985 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2986 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2988 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2997 /***********************************************************************
3000 * The idea is not to show the popup if the next input message is
3001 * going to hide it anyway.
3003 static BOOL FASTCALL
3004 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
3008 Msg
.hwnd
= Mt
->OwnerWnd
;
3010 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3011 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
3016 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3017 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
3019 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3020 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3021 if (WM_KEYDOWN
== Msg
.message
3022 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
3024 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3031 /* failures go through this */
3032 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3037 /***********************************************************************
3040 * Handle a VK_ESCAPE key event in a menu.
3042 static BOOL FASTCALL
3043 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3045 BOOL EndMenu
= TRUE
;
3046 ROSMENUINFO MenuInfo
;
3047 HMENU MenuTmp
, MenuPrev
;
3049 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3051 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3052 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
3054 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3056 /* close topmost popup */
3057 while (MenuTmp
!= Mt
->CurrentMenu
)
3060 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3063 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3065 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
3067 Mt
->CurrentMenu
= MenuPrev
;
3075 /***********************************************************************
3078 * Handle a VK_LEFT key event in a menu.
3080 static void FASTCALL
3081 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3083 ROSMENUINFO MenuInfo
;
3084 ROSMENUINFO TopMenuInfo
;
3085 ROSMENUINFO PrevMenuInfo
;
3086 HMENU MenuTmp
, MenuPrev
;
3089 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3091 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3096 /* Try to move 1 column left (if possible) */
3097 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3099 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3101 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3106 /* close topmost popup */
3107 while (MenuTmp
!= Mt
->CurrentMenu
)
3110 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3113 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3117 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
3118 Mt
->CurrentMenu
= MenuPrev
;
3120 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3124 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3126 /* move menu bar selection if no more popups are left */
3128 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
3130 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3133 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3135 /* A sublevel menu was displayed - display the next one
3136 * unless there is another displacement coming up */
3138 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3139 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3141 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3148 /***********************************************************************
3151 * Handle a VK_RIGHT key event in a menu.
3153 static void FASTCALL
3154 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3157 ROSMENUINFO MenuInfo
;
3158 ROSMENUINFO CurrentMenuInfo
;
3161 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3162 Mt
->CurrentMenu
, Mt
->TopMenu
);
3164 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3168 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3170 /* If already displaying a popup, try to display sub-popup */
3172 MenuTmp
= Mt
->CurrentMenu
;
3173 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3175 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3178 /* if subpopup was displayed then we are done */
3179 if (MenuTmp
!= Mt
->CurrentMenu
)
3185 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3190 /* Check to see if there's another column */
3191 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3193 TRACE("Going to %d.\n", NextCol
);
3194 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3196 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3201 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3203 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3205 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3206 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3213 /* try to move to the next item */
3214 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
3216 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3219 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3221 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3222 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3224 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3231 /***********************************************************************
3234 * Menu tracking code.
3237 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3238 HWND Wnd
, const RECT
*Rect
)
3241 ROSMENUINFO MenuInfo
;
3242 ROSMENUITEMINFO ItemInfo
;
3244 INT ExecutedMenuId
= -1;
3246 BOOL EnterIdleSent
= FALSE
;
3249 Mt
.CurrentMenu
= Menu
;
3255 TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3256 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3257 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3261 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3266 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3271 if (0 != (Flags
& TPM_BUTTONDOWN
))
3273 /* Get the result in order to start the tracking or not */
3274 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3275 fEndMenu
= ! fRemove
;
3278 SetCapture(Mt
.OwnerWnd
);
3279 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
.OwnerWnd
);
3281 ERR("MenuTrackMenu 1\n");
3284 PVOID menu
= ValidateHandle(Mt
.CurrentMenu
, VALIDATE_TYPE_MENU
);
3285 if (!menu
) /* sometimes happens if I do a window manager close */
3288 /* we have to keep the message in the queue until it's
3289 * clear that menu loop is not over yet. */
3293 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3295 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3299 /* remove the message from the queue */
3300 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3304 if (! EnterIdleSent
)
3306 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3307 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3308 EnterIdleSent
= TRUE
;
3309 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3315 /* check if EndMenu() tried to cancel us, by posting this message */
3316 if (Msg
.message
== WM_CANCELMODE
)
3318 /* we are now out of the loop */
3321 /* remove the message from the queue */
3322 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3324 /* break out of internal loop, ala ESCAPE */
3328 TranslateMessage(&Msg
);
3331 if (Msg
.hwnd
== MenuInfo
.Wnd
|| Msg
.message
!= WM_TIMER
)
3333 EnterIdleSent
= FALSE
;
3337 if ((Msg
.message
>= WM_MOUSEFIRST
) && (Msg
.message
<= WM_MOUSELAST
))
3340 * Use the mouse coordinates in lParam instead of those in the MSG
3341 * struct to properly handle synthetic messages. They are already
3342 * in screen coordinates.
3344 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3345 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3347 /* Find a menu for this mouse event */
3348 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3352 /* no WM_NC... messages in captured state */
3354 case WM_RBUTTONDBLCLK
:
3355 case WM_RBUTTONDOWN
:
3356 if (!(Flags
& TPM_RIGHTBUTTON
)) break;
3358 case WM_LBUTTONDBLCLK
:
3359 case WM_LBUTTONDOWN
:
3360 /* If the message belongs to the menu, removes it from the queue */
3361 /* Else, end menu tracking */
3362 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3363 fEndMenu
= ! fRemove
;
3367 if (0 == (Flags
& TPM_RIGHTBUTTON
)) break;
3370 /* Check if a menu was selected by the mouse */
3373 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3375 /* End the loop if ExecutedMenuId is an item ID */
3376 /* or if the job was done (ExecutedMenuId = 0). */
3377 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3381 /* No menu was selected by the mouse */
3382 /* if the function was called by TrackPopupMenu, continue
3383 with the menu tracking. If not, stop it */
3384 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3391 fEndMenu
|= !MenuMouseMove(&Mt
, Menu
, Flags
);
3395 } /* switch(Msg.message) - mouse */
3397 else if ((Msg
.message
>= WM_KEYFIRST
) && (Msg
.message
<= WM_KEYLAST
))
3399 fRemove
= TRUE
; /* Keyboard messages are always removed */
3411 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3413 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3415 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3416 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3421 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3422 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3424 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3426 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3428 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3432 else /* otherwise try to move selection */
3434 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3435 VK_DOWN
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3441 MenuKeyLeft(&Mt
, Flags
);
3445 MenuKeyRight(&Mt
, Flags
);
3449 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3455 hi
.cbSize
= sizeof(HELPINFO
);
3456 hi
.iContextType
= HELPINFO_MENUITEM
;
3457 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3459 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3465 MenuInitRosMenuItemInfo(&ItemInfo
);
3466 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3467 MenuInfo
.FocusedItem
,
3470 hi
.iCtrlId
= ItemInfo
.wID
;
3476 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3479 hi
.hItemHandle
= Menu
;
3480 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3481 hi
.MousePos
= Msg
.pt
;
3482 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3489 break; /* WM_KEYDOWN */
3496 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3500 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3502 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3503 fEndMenu
= (ExecutedMenuId
!= -2);
3507 /* Hack to avoid control chars. */
3508 /* We will find a better way real soon... */
3509 if (Msg
.wParam
< 32)
3514 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3515 LOWORD(Msg
.wParam
), FALSE
);
3516 if ((UINT
) -2 == Pos
)
3520 else if ((UINT
) -1 == Pos
)
3526 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3527 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3528 fEndMenu
= (-2 != ExecutedMenuId
);
3532 } /* switch(msg.message) - kbd */
3536 PeekMessageW( &Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3537 DispatchMessageW(&Msg
);
3546 /* finally remove message from the queue */
3548 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3550 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3554 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3557 ERR("MenuTrackMenu 2\n");
3559 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3560 SetCapture(NULL
); /* release the capture */
3562 /* If dropdown is still painted and the close box is clicked on
3563 then the menu will be destroyed as part of the DispatchMessage above.
3564 This will then invalidate the menu handle in Mt.hTopMenu. We should
3565 check for this first. */
3566 if (IsMenu(Mt
.TopMenu
))
3568 if (IsWindow(Mt
.OwnerWnd
))
3570 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3572 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3574 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3576 DestroyWindow(MenuInfo
.Wnd
);
3577 MenuInfo
.Wnd
= NULL
;
3579 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3580 SendMessageW( Mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)Mt
.TopMenu
,
3581 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3584 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3587 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3590 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3592 /* Reset the variable for hiding menu */
3593 MenuInfo
.TimeToHide
= FALSE
;
3594 MenuSetRosMenuInfo(&MenuInfo
);
3598 /* The return value is only used by TrackPopupMenu */
3599 if (!(Flags
& TPM_RETURNCMD
)) return TRUE
;
3600 if (ExecutedMenuId
< 0) ExecutedMenuId
= 0;
3601 return ExecutedMenuId
;
3604 /***********************************************************************
3607 static BOOL FASTCALL
3608 MenuExitTracking(HWND Wnd
)
3610 TRACE("hwnd=%p\n", Wnd
);
3612 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3619 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3621 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3622 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3624 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, Pt
.x
, Pt
.y
);
3628 /* map point to parent client coordinates */
3629 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3630 if (Parent
!= GetDesktopWindow())
3632 ScreenToClient(Parent
, &Pt
);
3635 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3636 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3637 MenuExitTracking(Wnd
);
3643 MenuTrackKbdMenuBar(HWND hWnd
, UINT wParam
, WCHAR wChar
)
3645 UINT uItem
= NO_SELECTED_ITEM
;
3647 ROSMENUINFO MenuInfo
;
3648 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3650 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd
, wParam
, wChar
);
3652 /* find window that has a menu */
3654 while (!((GetWindowLongPtrW( hWnd
, GWL_STYLE
) &
3655 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3656 if (!(hWnd
= GetAncestor( hWnd
, GA_PARENT
))) return;
3658 /* check if we have to track a system menu */
3660 hTrackMenu
= GetMenu( hWnd
);
3661 if (!hTrackMenu
|| IsIconic(hWnd
) || wChar
== ' ' )
3663 if (!(GetWindowLongPtrW( hWnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3664 hTrackMenu
= NtUserGetSystemMenu(hWnd
, FALSE
);
3666 wParam
|= HTSYSMENU
; /* prevent item lookup */
3669 if (!IsMenu( hTrackMenu
)) return;
3671 MenuInitTracking( hWnd
, hTrackMenu
, FALSE
, wFlags
);
3673 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3678 if( wChar
&& wChar
!= ' ' )
3680 uItem
= MenuFindItemByKey( hWnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3681 if ( uItem
>= (UINT
)(-2) )
3683 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3684 /* schedule end of menu tracking */
3685 wFlags
|= TF_ENDMENU
;
3690 MenuSelectItem( hWnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3692 if (wParam
& HTSYSMENU
)
3694 /* prevent sysmenu activation for managed windows on Alt down/up */
3695 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3696 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3700 if( uItem
== NO_SELECTED_ITEM
)
3701 MenuMoveSelection( hWnd
, &MenuInfo
, ITEM_NEXT
);
3703 PostMessageW( hWnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3707 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hWnd
, NULL
);
3708 MenuExitTracking( hWnd
);
3714 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3715 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3717 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3719 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3720 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3721 * MFT_STRING is replaced by MIIM_STRING.
3722 * (So, I guess we should use MIIM_STRING only for strings?)
3724 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3726 * Based on wine, SetMenuItemInfo_common:
3727 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3728 * it will result in a error.
3729 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3730 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3737 LPMENUITEMINFOW mii
,
3744 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3746 if(Flags
& MF_BITMAP
)
3748 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3749 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3751 if (Flags
& MF_HELP
)
3753 /* increase ident */
3754 mii
->fType
|= MF_HELP
;
3757 else if(Flags
& MF_OWNERDRAW
)
3759 mii
->fType
|= MFT_OWNERDRAW
;
3760 mii
->fMask
|= MIIM_DATA
;
3761 mii
->dwItemData
= (DWORD
) NewItem
;
3763 else if (Flags
& MF_SEPARATOR
)
3765 mii
->fType
|= MFT_SEPARATOR
;
3766 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3767 Flags
|= MF_GRAYED
|MF_DISABLED
;
3769 else /* Default action MF_STRING. */
3771 /* Item beginning with a backspace is a help item */
3772 if (NewItem
!= NULL
)
3776 if (*NewItem
== '\b')
3778 mii
->fType
|= MF_HELP
;
3784 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3785 if (*NewItemA
== '\b')
3787 mii
->fType
|= MF_HELP
;
3789 NewItem
= (LPCWSTR
) NewItemA
;
3793 if (Flags
& MF_HELP
)
3794 mii
->fType
|= MF_HELP
;
3795 mii
->fMask
|= MIIM_STRING
;
3796 mii
->fType
|= MFT_STRING
; /* Zero */
3797 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3799 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3801 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3805 mii
->fType
|= MFT_SEPARATOR
;
3806 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3807 Flags
|= MF_GRAYED
|MF_DISABLED
;
3811 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3813 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3816 if(Flags
& MF_MENUBREAK
)
3818 mii
->fType
|= MFT_MENUBREAK
;
3820 else if(Flags
& MF_MENUBARBREAK
)
3822 mii
->fType
|= MFT_MENUBARBREAK
;
3825 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3827 if (Flags
& MF_GRAYED
)
3828 mii
->fState
|= MF_GRAYED
;
3830 if (Flags
& MF_DISABLED
)
3831 mii
->fState
|= MF_DISABLED
;
3833 mii
->fMask
|= MIIM_STATE
;
3835 else if (Flags
& MF_HILITE
)
3837 mii
->fState
|= MF_HILITE
;
3838 mii
->fMask
|= MIIM_STATE
;
3840 else /* default state */
3842 mii
->fState
|= MFS_ENABLED
;
3843 mii
->fMask
|= MIIM_STATE
;
3846 if(Flags
& MF_POPUP
)
3848 mii
->fType
|= MF_POPUP
;
3849 mii
->fMask
|= MIIM_SUBMENU
;
3850 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3854 mii
->fMask
|= MIIM_ID
;
3855 mii
->wID
= (UINT
)IDNewItem
;
3861 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3863 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3866 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3868 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3869 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3870 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3871 (LPCWSTR
)&Common
->MenuName
);
3873 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3877 /* FUNCTIONS *****************************************************************/
3880 MenuIsStringItem(ULONG TypeData)
3882 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3890 AppendMenuA(HMENU hMenu
,
3892 UINT_PTR uIDNewItem
,
3895 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3904 AppendMenuW(HMENU hMenu
,
3906 UINT_PTR uIDNewItem
,
3909 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3918 CheckMenuItem(HMENU hmenu
,
3922 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3927 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3930 PROSMENUITEMINFO Items
= NULL
;
3931 UINT cChecked
, cUnchecked
;
3935 if(idFirst
> idLast
)
3938 ItemCount
= GetMenuItemCount(hMenu
);
3940 //mi.cbSize = sizeof(ROSMENUINFO);
3941 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3944 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3946 ERR("MenuGetAllRosMenuItemInfo failed\n");
3950 cChecked
= cUnchecked
= 0;
3952 for (i
= 0 ; i
< ItemCount
; i
++)
3955 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3956 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3958 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3960 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3963 if (uFlags
& MF_BYPOSITION
)
3965 if (i
< idFirst
|| i
> idLast
)
3980 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3983 if (Items
[i
].wID
== idCheck
)
3997 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4000 Items
[i
].fType
|= MFT_RADIOCHECK
;
4001 Items
[i
].fState
|= MFS_CHECKED
;
4005 Items
[i
].fState
&= ~MFS_CHECKED
;
4008 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4010 ERR("MenuSetRosMenuItemInfo failed\n");
4015 HeapFree(GetProcessHeap(), 0, Items
);
4017 *pChecked
+= cChecked
;
4018 *pUnchecked
+= cUnchecked
;
4020 if (cChecked
|| cUnchecked
)
4030 CheckMenuRadioItem(HMENU hmenu
,
4037 UINT cUnchecked
= 0;
4038 UINT cMenuChanged
= 0;
4040 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4043 if (cMenuChanged
> 1)
4050 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4053 return (cChecked
!= 0);
4064 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4072 CreatePopupMenu(VOID
)
4075 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4083 DrawMenuBar(HWND hWnd
)
4085 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4086 ROSMENUINFO MenuInfo
;
4088 hMenu
= GetMenu(hWnd
);
4091 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4092 MenuInfo
.Height
= 0; // make sure to recalc size
4093 MenuSetRosMenuInfo(&MenuInfo
);
4094 /* The wine method doesn't work and I suspect it's more effort
4095 then hackfix solution
4096 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4097 SWP_NOZORDER | SWP_FRAMECHANGED );
4100 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4109 EnableMenuItem(HMENU hMenu
,
4113 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4123 guii
.cbSize
= sizeof(GUITHREADINFO
);
4124 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4126 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4138 PWND Wnd
= ValidateHwnd(hWnd
);
4143 return (HMENU
)Wnd
->IDMenu
;
4151 GetMenuCheckMarkDimensions(VOID
)
4153 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4154 GetSystemMetrics(SM_CYMENUCHECK
)));
4162 GetMenuDefaultItem(HMENU hMenu
,
4166 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4174 GetMenuInfo(HMENU hmenu
,
4180 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4183 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4184 mi
.cbSize
= sizeof(MENUINFO
);
4185 mi
.fMask
= lpcmi
->fMask
;
4187 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4189 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4198 GetMenuItemCount(HMENU Menu
)
4200 ROSMENUINFO MenuInfo
;
4202 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4210 GetMenuItemID(HMENU hMenu
,
4213 ROSMENUITEMINFO mii
;
4215 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4216 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4218 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4223 if (NULL
!= mii
.hSubMenu
)
4244 LPMENUITEMINFOA mii
)
4250 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4251 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4253 SetLastError(ERROR_INVALID_PARAMETER
);
4257 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4259 /* No text requested, just pass on */
4260 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4263 AnsiBuffer
= mii
->dwTypeData
;
4264 Count
= miiW
.cch
= mii
->cch
;
4265 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4266 miiW
.dwTypeData
= 0;
4270 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4271 miiW
.cch
* sizeof(WCHAR
));
4272 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4273 miiW
.dwTypeData
[0] = 0;
4276 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4278 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4282 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4284 if (!AnsiBuffer
|| !Count
)
4286 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4287 mii
->dwTypeData
= AnsiBuffer
;
4288 mii
->cch
= miiW
.cch
;
4292 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4296 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4300 if (Count
> miiW
.cch
)
4302 AnsiBuffer
[miiW
.cch
] = 0;
4304 mii
->cch
= mii
->cch
;
4312 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4313 mii
->dwTypeData
= AnsiBuffer
;
4327 LPMENUITEMINFOW mii
)
4333 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4334 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4336 SetLastError(ERROR_INVALID_PARAMETER
);
4340 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4342 /* No text requested, just pass on */
4343 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4346 String
= mii
->dwTypeData
;
4348 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4349 miiW
.dwTypeData
= 0;
4353 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4354 miiW
.cch
* sizeof(WCHAR
));
4355 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4356 miiW
.dwTypeData
[0] = 0;
4359 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4361 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4365 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4367 if (!String
|| !Count
)
4369 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4370 mii
->dwTypeData
= String
; // may not be zero.
4371 mii
->cch
= miiW
.cch
;
4375 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4377 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4380 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4381 mii
->dwTypeData
= String
;
4382 mii
->cch
= strlenW(String
);
4397 ROSMENUINFO MenuInfo
;
4398 ROSMENUITEMINFO mii
;
4399 memset( &mii
, 0, sizeof(mii
) );
4400 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4401 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4404 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4409 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4413 nSubItems
= MenuInfo
.MenuItemCount
;
4415 /* FIXME - ported from wine, does that work (0xff)? */
4416 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4417 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4419 return (UINT
)-1; /* Invalid submenu */
4422 /* FIXME - ported from wine, does that work? */
4423 return (mii
.fType
| mii
.fState
);
4443 memset( &mii
, 0, sizeof(mii
) );
4444 mii
.dwTypeData
= lpString
;
4445 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4446 mii
.fType
= MFT_STRING
;
4447 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4448 mii
.cch
= nMaxCount
;
4450 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4470 memset( &miiW
, 0, sizeof(miiW
) );
4471 miiW
.dwTypeData
= lpString
;
4472 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4473 miiW
.fType
= MFT_STRING
;
4474 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4475 miiW
.cch
= nMaxCount
;
4477 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4495 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4496 mi
.fMask
= MIIM_SUBMENU
;
4498 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4500 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4517 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4519 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4532 UINT_PTR uIDNewItem
,
4536 memset( &mii
, 0, sizeof(mii
) );
4537 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4538 mii
.fMask
= MIIM_FTYPE
;
4540 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4543 (LPCWSTR
) lpNewItem
,
4546 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4560 LPCMENUITEMINFOA lpmii
)
4563 UNICODE_STRING MenuText
;
4565 BOOL CleanHeap
= FALSE
;
4568 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4569 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4571 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4573 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4575 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4578 /* copy the text string */
4579 if (((mi
.fMask
& MIIM_STRING
) ||
4580 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4581 && mi
.dwTypeData
!= NULL
)
4583 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4584 if (!NT_SUCCESS (Status
))
4586 SetLastError (RtlNtStatusToDosError(Status
));
4589 mi
.dwTypeData
= MenuText
.Buffer
;
4590 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4593 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4595 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4610 LPCMENUITEMINFOW lpmii
)
4613 UNICODE_STRING MenuText
;
4616 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4617 if a bad user passes bad data, we crash his process instead of the
4620 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4621 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4623 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4625 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4627 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4630 /* copy the text string */
4631 if (((mi
.fMask
& MIIM_STRING
) ||
4632 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4633 && mi
.dwTypeData
!= NULL
)
4635 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4636 mi
.dwTypeData
= MenuText
.Buffer
;
4637 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4639 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4654 UINT_PTR uIDNewItem
,
4658 memset( &mii
, 0, sizeof(mii
) );
4659 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4660 mii
.fMask
= MIIM_FTYPE
;
4662 MenuSetItemData( &mii
,
4668 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4680 if (ValidateHandle(Menu
, VALIDATE_TYPE_MENU
)) return TRUE
;
4689 LoadMenuA(HINSTANCE hInstance
,
4692 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4693 if (Resource
== NULL
)
4697 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4705 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4707 return(LoadMenuIndirectW(lpMenuTemplate
));
4715 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4718 WORD version
, offset
;
4719 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4721 version
= GET_WORD(p
);
4726 case 0: /* standard format is version of 0 */
4727 offset
= GET_WORD(p
);
4728 p
+= sizeof(WORD
) + offset
;
4729 if (!(hMenu
= CreateMenu())) return 0;
4730 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4736 case 1: /* extended format is version of 1 */
4737 offset
= GET_WORD(p
);
4738 p
+= sizeof(WORD
) + offset
;
4739 if (!(hMenu
= CreateMenu())) return 0;
4740 if (!MENUEX_ParseResource(p
, hMenu
))
4742 DestroyMenu( hMenu
);
4747 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4757 LoadMenuW(HINSTANCE hInstance
,
4760 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4761 if (Resource
== NULL
)
4765 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4779 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4792 UINT_PTR uIDNewItem
,
4796 ROSMENUITEMINFO rmii
;
4798 memset( &mii
, 0, sizeof(mii
) );
4799 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4800 mii
.fMask
= MIIM_FTYPE
;
4802 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4806 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4808 MenuInitRosMenuItemInfo( &rmii
);
4810 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4812 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4813 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4815 MenuCleanupRosMenuItemInfo( &rmii
);
4817 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4820 (LPCWSTR
) lpNewItem
,
4823 return SetMenuItemInfoA( hMnu
,
4825 (BOOL
)(MF_BYPOSITION
& uFlags
),
4839 UINT_PTR uIDNewItem
,
4843 ROSMENUITEMINFO rmii
;
4845 memset ( &mii
, 0, sizeof(mii
) );
4846 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4847 mii
.fMask
= MIIM_FTYPE
;
4849 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4851 mi
.Height
= 0; // Force size recalculation.
4853 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4855 MenuInitRosMenuItemInfo( &rmii
);
4857 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4859 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4860 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4862 MenuCleanupRosMenuItemInfo( &rmii
);
4864 /* Init new data for this menu item */
4865 MenuSetItemData( &mii
,
4871 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4872 return SetMenuItemInfoW( hMnu
,
4874 (BOOL
)(MF_BYPOSITION
& uFlags
),
4886 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4902 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4904 SetLastError(ERROR_INVALID_PARAMETER
);
4908 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4909 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4922 HBITMAP hBitmapUnchecked
,
4923 HBITMAP hBitmapChecked
)
4925 ROSMENUITEMINFO uItem
;
4926 memset ( &uItem
, 0, sizeof(uItem
) );
4927 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4929 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4930 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4932 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4934 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4936 else /* Install new bitmaps */
4938 uItem
.hbmpChecked
= hBitmapChecked
;
4939 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4940 uItem
.fState
|= MF_USECHECKBITMAPS
;
4942 return NtUserMenuItemInfo(hMenu
, uPosition
,
4943 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4956 LPCMENUITEMINFOA lpmii
)
4958 MENUITEMINFOW MenuItemInfoW
;
4959 UNICODE_STRING UnicodeString
;
4961 ULONG Result
= FALSE
;
4963 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4965 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4967 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4968 MenuItemInfoW
.hbmpItem
= NULL
;
4971 * MIIM_STRING == good
4972 * MIIM_TYPE & MFT_STRING == good
4973 * MIIM_STRING & MFT_STRING == good
4974 * MIIM_STRING & MFT_OWNERSRAW == good
4976 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4977 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4978 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4979 && MenuItemInfoW
.dwTypeData
!= NULL
)
4981 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
4982 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
4983 (LPSTR
)MenuItemInfoW
.dwTypeData
);
4984 if (!NT_SUCCESS (Status
))
4986 SetLastError (RtlNtStatusToDosError(Status
));
4989 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
4990 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4994 UnicodeString
.Buffer
= NULL
;
4997 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
4998 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5000 if (UnicodeString
.Buffer
!= NULL
)
5002 RtlFreeUnicodeString(&UnicodeString
);
5018 LPCMENUITEMINFOW lpmii
)
5020 MENUITEMINFOW MenuItemInfoW
;
5023 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5025 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5027 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5028 MenuItemInfoW
.hbmpItem
= NULL
;
5031 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5032 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5033 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5034 && MenuItemInfoW
.dwTypeData
!= NULL
)
5036 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5038 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5039 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5055 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5060 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5063 return NtUserSetSystemMenu(hwnd
, hMenu
);
5085 SetLastError( ERROR_INVALID_MENU_HANDLE
);
5089 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
5091 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
5092 if (0 == (Flags
& TPM_NONOTIFY
))
5094 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5097 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
5099 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5101 MenuExitTracking(Wnd
);
5119 /* Not fully implemented */
5120 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5121 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5125 // Example for the Win32/User32 rewrite.
5126 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5140 return NtUserTrackPopupMenuEx( Menu
,
5145 NULL
); // LPTPMPARAMS is null
5154 GetMenuContextHelpId(HMENU hmenu
)
5157 mi
.cbSize
= sizeof(ROSMENUINFO
);
5158 mi
.fMask
= MIM_HELPID
;
5160 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5162 return mi
.dwContextHelpID
;
5183 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5186 Result
= (ULONG_PTR
)lResult
;
5191 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5211 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5214 Result
= (ULONG_PTR
)lResult
;
5219 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5230 LPCWSTR lpszNewItem
,
5235 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5236 for MF_DELETE. We should check the parameters for all others
5237 MF_* actions also (anybody got a doc on ChangeMenu?).
5240 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5243 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5246 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5249 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5252 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5253 flags
&~ MF_REMOVE
);
5255 default : /* MF_INSERT */
5256 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5273 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5274 for MF_DELETE. We should check the parameters for all others
5275 MF_* actions also (anybody got a doc on ChangeMenu?).
5278 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5281 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5284 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5287 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5290 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5291 flags
&~ MF_REMOVE
);
5293 default : /* MF_INSERT */
5294 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);