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. */
60 static HWND top_popup
;
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 a Sub menu. Return the position of the submenu, and modifies
356 * *hmenu in case it is found in another sub-menu.
357 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
359 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
363 ROSMENUITEMINFO item
;
365 if (((*hmenu
)==(HMENU
)0xffff) ||
366 (!MenuGetRosMenuInfo(&menu
, *hmenu
)))
367 return NO_SELECTED_ITEM
;
369 MenuInitRosMenuItemInfo(&item
);
370 for (i
= 0; i
< menu
.MenuItemCount
; i
++)
372 if (! MenuGetRosMenuItemInfo(menu
.Self
, i
, &item
))
374 MenuCleanupRosMenuItemInfo(&item
);
375 return NO_SELECTED_ITEM
;
377 if (!(item
.fType
& MF_POPUP
)) continue;
378 if (item
.hSubMenu
== hSubTarget
) {
379 MenuCleanupRosMenuItemInfo(&item
);
383 HMENU hsubmenu
= item
.hSubMenu
;
384 UINT pos
= MenuFindSubMenu(&hsubmenu
, hSubTarget
);
385 if (pos
!= NO_SELECTED_ITEM
) {
391 MenuCleanupRosMenuItemInfo(&item
);
392 return NO_SELECTED_ITEM
;
395 /***********************************************************************
398 * Find the menu item selected by a key press.
399 * Return item id, -1 if none, -2 if we should close the menu.
401 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
402 WCHAR Key
, BOOL ForceMenuChar
)
404 ROSMENUINFO SysMenuInfo
;
405 PROSMENUITEMINFO Items
, ItemInfo
;
409 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
411 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
413 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
415 MenuInfo
= &SysMenuInfo
;
423 if (NULL
!= MenuInfo
)
425 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
433 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
435 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
437 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
440 p
= strchrW(p
+ 2, '&');
442 while (NULL
!= p
&& L
'&' == p
[1]);
443 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
451 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
452 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
453 if (2 == HIWORD(MenuChar
))
455 return LOWORD(MenuChar
);
457 if (1 == HIWORD(MenuChar
))
466 /***********************************************************************
467 * MenuGetBitmapItemSize
469 * Get the size of a bitmap item.
471 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
,
475 HBITMAP bmp
= lpitem
->hbmpItem
;
477 size
->cx
= size
->cy
= 0;
479 /* check if there is a magic menu item associated with this item */
480 if (IS_MAGIC_BITMAP(bmp
))
482 switch((INT_PTR
) bmp
)
484 case (INT_PTR
)HBMMENU_CALLBACK
:
486 MEASUREITEMSTRUCT measItem
;
487 measItem
.CtlType
= ODT_MENU
;
489 measItem
.itemID
= lpitem
->wID
;
490 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
491 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
492 measItem
.itemData
= lpitem
->dwItemData
;
493 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
494 size
->cx
= measItem
.itemWidth
;
495 size
->cy
= measItem
.itemHeight
;
500 case (INT_PTR
) HBMMENU_SYSTEM
:
501 if (0 != lpitem
->dwItemData
)
503 bmp
= (HBITMAP
) lpitem
->dwItemData
;
507 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
508 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
509 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
510 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
511 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
512 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
513 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
514 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
515 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
516 /* FIXME: Why we need to subtract these magic values? */
517 /* to make them smaller than the menu bar? */
518 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
519 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
524 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
526 size
->cx
= bm
.bmWidth
;
527 size
->cy
= bm
.bmHeight
;
531 /***********************************************************************
534 * Draw a bitmap item.
536 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
537 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
543 int w
= rect
->right
- rect
->left
;
544 int h
= rect
->bottom
- rect
->top
;
547 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
550 /* Check if there is a magic menu item associated with this item */
551 if (IS_MAGIC_BITMAP(hbmToDraw
))
557 switch ((INT_PTR
)hbmToDraw
)
559 case (INT_PTR
)HBMMENU_SYSTEM
:
560 if (lpitem
->dwTypeData
)
562 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
563 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
567 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
569 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
570 /* only use right half of the bitmap */
571 bmp_xoffset
= bm
.bmWidth
/ 2;
572 bm
.bmWidth
-= bmp_xoffset
;
575 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
576 flags
= DFCS_CAPTIONRESTORE
;
578 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
580 flags
= DFCS_CAPTIONMIN
;
582 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
584 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
586 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
587 flags
= DFCS_CAPTIONCLOSE
;
589 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
590 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
592 case (INT_PTR
)HBMMENU_CALLBACK
:
594 DRAWITEMSTRUCT drawItem
;
596 drawItem
.CtlType
= ODT_MENU
;
598 drawItem
.itemID
= lpitem
->wID
;
599 drawItem
.itemAction
= odaction
;
600 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
601 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
602 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
603 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
604 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
605 drawItem
.hwndItem
= (HWND
)hmenu
;
607 drawItem
.rcItem
= *rect
;
608 drawItem
.itemData
= lpitem
->dwItemData
;
609 /* some applications make this assumption on the DC's origin */
610 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
611 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
612 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
613 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
618 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
619 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
620 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
621 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
622 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
625 InflateRect(&r
, -1, -1);
626 if (0 != (lpitem
->fState
& MF_HILITE
))
628 flags
|= DFCS_PUSHED
;
630 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
634 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
637 hdcMem
= CreateCompatibleDC( hdc
);
638 SelectObject( hdcMem
, bmp
);
640 /* handle fontsize > bitmap_height */
641 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
643 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
644 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
645 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
646 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
650 /***********************************************************************
653 * Calculate the size of the menu item and store it in lpitem->rect.
655 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
656 INT orgX
, INT orgY
, BOOL menuBar
)
659 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
662 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
664 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
666 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
668 if (lpitem
->fType
& MF_OWNERDRAW
)
670 MEASUREITEMSTRUCT mis
;
671 mis
.CtlType
= ODT_MENU
;
673 mis
.itemID
= lpitem
->wID
;
674 mis
.itemData
= lpitem
->dwItemData
;
675 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
677 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
678 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
679 * width of a menufont character to the width of an owner-drawn menu.
681 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
684 /* under at least win95 you seem to be given a standard
685 height for the menu and the height value is ignored */
686 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
688 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
690 TRACE("id=%04lx size=%dx%d\n",
691 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
695 if (lpitem
->fType
& MF_SEPARATOR
)
697 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
699 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
705 if (lpitem
->hbmpItem
)
710 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
711 /* Keep the size of the bitmap in callback mode to be able
712 * to draw it correctly */
713 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
714 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
715 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
717 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
718 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
720 MenuSetRosMenuInfo(MenuInfo
);
721 itemheight
= size
.cy
+ 2;
723 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
724 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
725 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
726 lpitem
->XTab
= lpitem
->Rect
.right
;
727 lpitem
->Rect
.right
+= check_bitmap_width
;
728 } else /* hbmpItem & MenuBar */ {
729 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
730 lpitem
->Rect
.right
+= size
.cx
;
731 if( lpitem
->Text
) lpitem
->Rect
.right
+= 2;
732 itemheight
= size
.cy
;
734 /* Special case: Minimize button doesn't have a space behind it. */
735 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
736 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
737 lpitem
->Rect
.right
-= 1;
741 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
742 lpitem
->Rect
.right
+= check_bitmap_width
;
743 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
744 lpitem
->XTab
= lpitem
->Rect
.right
;
745 lpitem
->Rect
.right
+= check_bitmap_width
;
748 /* it must be a text item - unless it's the system menu */
749 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Text
) {
750 HFONT hfontOld
= NULL
;
751 RECT rc
= lpitem
->Rect
;
752 LONG txtheight
, txtwidth
;
754 if ( lpitem
->fState
& MFS_DEFAULT
) {
755 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
758 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
759 DT_SINGLELINE
|DT_CALCRECT
);
760 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
761 itemheight
= max( max( itemheight
, txtheight
),
762 GetSystemMetrics( SM_CYMENU
) - 1);
763 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
765 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
768 int n
= (int)( p
- lpitem
->dwTypeData
);
769 /* Item contains a tab (only meaningful in popup menus) */
770 /* get text size before the tab */
771 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
772 DT_SINGLELINE
|DT_CALCRECT
);
773 txtwidth
= rc
.right
- rc
.left
;
774 p
+= 1; /* advance past the Tab */
775 /* get text size after the tab */
776 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
777 DT_SINGLELINE
|DT_CALCRECT
);
778 lpitem
->XTab
+= txtwidth
;
779 txtheight
= max( txtheight
, tmpheight
);
780 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
781 tmprc
.right
- tmprc
.left
; /* space for the short cut */
783 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
784 DT_SINGLELINE
|DT_CALCRECT
);
785 txtwidth
= rc
.right
- rc
.left
;
786 lpitem
->XTab
+= txtwidth
;
788 lpitem
->Rect
.right
+= 2 + txtwidth
;
789 itemheight
= max( itemheight
,
790 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
792 if (hfontOld
) SelectObject (hdc
, hfontOld
);
793 } else if( menuBar
) {
794 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
796 lpitem
->Rect
.bottom
+= itemheight
;
797 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
800 /***********************************************************************
801 * MenuPopupMenuCalcSize
803 * Calculate the size of a popup menu.
805 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
807 ROSMENUITEMINFO lpitem
;
810 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
812 MenuInfo
->Width
= MenuInfo
->Height
= 0;
813 if (MenuInfo
->MenuItemCount
== 0)
815 MenuSetRosMenuInfo(MenuInfo
);
820 SelectObject( hdc
, hMenuFont
);
825 MenuInfo
->maxBmpSize
.cx
= 0;
826 MenuInfo
->maxBmpSize
.cy
= 0;
828 MenuInitRosMenuItemInfo(&lpitem
);
829 while (start
< MenuInfo
->MenuItemCount
)
834 maxTab
= maxTabWidth
= 0;
836 /* Parse items until column break or end of menu */
837 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
839 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
841 MenuCleanupRosMenuItemInfo(&lpitem
);
842 MenuSetRosMenuInfo(MenuInfo
);
846 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
848 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
849 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
851 MenuCleanupRosMenuItemInfo(&lpitem
);
852 MenuSetRosMenuInfo(MenuInfo
);
855 // Not sure here,, The patch from wine removes this.
856 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
860 maxX
= max(maxX
, lpitem
.Rect
.right
);
861 orgY
= lpitem
.Rect
.bottom
;
862 if ((lpitem
.Text
) && lpitem
.XTab
)
864 maxTab
= max( maxTab
, lpitem
.XTab
);
865 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.XTab
);
869 /* Finish the column (set all items to the largest width found) */
870 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
873 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
875 lpitem
.Rect
.right
= maxX
;
876 if ((lpitem
.Text
) && 0 != lpitem
.XTab
)
878 lpitem
.XTab
= maxTab
;
880 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
884 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
887 MenuInfo
->Width
= maxX
;
889 /* space for 3d border */
890 MenuInfo
->Height
+= 2;
891 MenuInfo
->Width
+= 2;
893 MenuCleanupRosMenuItemInfo(&lpitem
);
894 MenuSetRosMenuInfo(MenuInfo
);
898 /***********************************************************************
899 * MenuMenuBarCalcSize
901 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
902 * height is off by 1 pixel which causes lengthy window relocations when
903 * active document window is maximized/restored.
905 * Calculate the size of the menu bar.
907 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
908 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
910 ROSMENUITEMINFO ItemInfo
;
911 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
913 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
914 if (MenuInfo
->MenuItemCount
== 0) return;
915 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
916 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
917 MenuInfo
->Height
= 0;
918 maxY
= lprect
->top
+ 1;
922 MenuInfo
->maxBmpSize
.cx
= 0;
923 MenuInfo
->maxBmpSize
.cy
= 0;
925 MenuInitRosMenuItemInfo(&ItemInfo
);
926 while (start
< MenuInfo
->MenuItemCount
)
928 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
930 MenuCleanupRosMenuItemInfo(&ItemInfo
);
936 /* Parse items until line break or end of menu */
937 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
939 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
941 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
943 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
944 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
945 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
947 MenuCleanupRosMenuItemInfo(&ItemInfo
);
951 if (ItemInfo
.Rect
.right
> lprect
->right
)
953 if (i
!= start
) break;
954 else ItemInfo
.Rect
.right
= lprect
->right
;
956 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
957 orgX
= ItemInfo
.Rect
.right
;
958 if (i
+ 1 < MenuInfo
->MenuItemCount
)
960 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
962 MenuCleanupRosMenuItemInfo(&ItemInfo
);
968 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
969 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
971 /* Finish the line (set all items to the largest height found) */
974 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
976 ItemInfo
.Rect
.bottom
= maxY
;
977 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
982 start
= i
; /* This works! */
986 lprect
->bottom
= maxY
;
987 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
988 MenuSetRosMenuInfo(MenuInfo
);
992 /* Flush right all items between the MF_RIGHTJUSTIFY and */
993 /* the last item (if several lines, only move the last line) */
994 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
996 MenuCleanupRosMenuItemInfo(&ItemInfo
);
999 orgY
= ItemInfo
.Rect
.top
;
1000 orgX
= lprect
->right
;
1001 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1007 if (ItemInfo
.Rect
.top
!= orgY
)
1009 break; /* Other line */
1011 if (orgX
<= ItemInfo
.Rect
.right
)
1013 break; /* Too far right already */
1015 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1016 ItemInfo
.Rect
.right
= orgX
;
1017 orgX
= ItemInfo
.Rect
.left
;
1018 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1019 if (helpPos
+ 1 <= i
&&
1020 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1022 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1028 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1031 /***********************************************************************
1034 * Draw a single menu item.
1036 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1037 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1041 BOOL flat_menu
= FALSE
;
1043 PWND Wnd
= ValidateHwnd(hWnd
);
1048 if (lpitem
->fType
& MF_SYSMENU
)
1050 if ( (Wnd
->style
& WS_MINIMIZE
))
1052 UserGetInsideRectNC(Wnd
, &rect
);
1053 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1054 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1059 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1060 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1064 if (lpitem
->fState
& MF_HILITE
)
1066 if(menuBar
&& !flat_menu
) {
1067 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1068 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1070 if (lpitem
->fState
& MF_GRAYED
)
1071 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1073 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1074 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1079 if (lpitem
->fState
& MF_GRAYED
)
1080 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1082 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1083 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1086 rect
= lpitem
->Rect
;
1088 if (lpitem
->fType
& MF_OWNERDRAW
)
1091 ** Experimentation under Windows reveals that an owner-drawn
1092 ** menu is given the rectangle which includes the space it requested
1093 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1094 ** and a popup-menu arrow. This is the value of lpitem->rect.
1095 ** Windows will leave all drawing to the application except for
1096 ** the popup-menu arrow. Windows always draws that itself, after
1097 ** the menu owner has finished drawing.
1101 dis
.CtlType
= ODT_MENU
;
1103 dis
.itemID
= lpitem
->wID
;
1104 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1106 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1107 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1108 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1109 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1110 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1113 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1114 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1115 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1116 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1118 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1119 /* Draw the popup-menu arrow */
1120 if (lpitem
->fType
& MF_POPUP
)
1123 CopyRect(&rectTemp
, &rect
);
1124 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1125 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1130 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1132 if (lpitem
->fState
& MF_HILITE
)
1136 InflateRect (&rect
, -1, -1);
1137 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1138 InflateRect (&rect
, 1, 1);
1139 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1144 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1146 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1150 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1152 SetBkMode( hdc
, TRANSPARENT
);
1154 /* vertical separator */
1155 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1162 rc
.bottom
= Height
- 3;
1165 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1166 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1167 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1168 LineTo( hdc
, rc
.left
, rc
.bottom
);
1169 SelectObject( hdc
, oldPen
);
1172 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1175 /* horizontal separator */
1176 if (lpitem
->fType
& MF_SEPARATOR
)
1183 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1186 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1187 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1188 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1189 LineTo( hdc
, rc
.right
, rc
.top
);
1190 SelectObject( hdc
, oldPen
);
1193 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1198 /* helper lines for debugging */
1199 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1200 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1201 SelectObject(hdc
, GetStockObject(DC_PEN
));
1202 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1203 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1204 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1210 INT y
= rect
.top
+ rect
.bottom
;
1212 int checked
= FALSE
;
1213 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1214 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1215 /* Draw the check mark
1218 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1220 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1221 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1222 lpitem
->hbmpUnchecked
;
1223 if (bm
) /* we have a custom bitmap */
1225 HDC hdcMem
= CreateCompatibleDC( hdc
);
1227 SelectObject( hdcMem
, bm
);
1228 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1229 check_bitmap_width
, check_bitmap_height
,
1230 hdcMem
, 0, 0, SRCCOPY
);
1234 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1237 CopyRect(&r
, &rect
);
1238 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1239 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1240 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1241 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1245 if ( lpitem
->hbmpItem
)
1248 CopyRect(&bmpRect
, &rect
);
1249 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1250 bmpRect
.left
+= check_bitmap_width
+ 2;
1251 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1253 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1254 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1257 /* Draw the popup-menu arrow */
1258 if (lpitem
->fType
& MF_POPUP
)
1261 CopyRect(&rectTemp
, &rect
);
1262 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1263 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1266 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1267 rect
.left
+= check_bitmap_width
;
1268 rect
.right
-= check_bitmap_width
;
1270 else if( lpitem
->hbmpItem
)
1271 { /* Draw the bitmap */
1272 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1275 /* process text if present */
1281 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1282 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1284 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1285 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1287 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1289 if ( lpitem
->fState
& MFS_DEFAULT
)
1291 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1295 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1296 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1299 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1302 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1303 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1307 if(lpitem
->fState
& MF_GRAYED
)
1309 if (!(lpitem
->fState
& MF_HILITE
) )
1311 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1312 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1313 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1314 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1316 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1319 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1321 /* paint the shortcut text */
1322 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1324 if (L
'\t' == Text
[i
])
1326 rect
.left
= lpitem
->XTab
;
1327 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1331 rect
.right
= lpitem
->XTab
;
1332 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1335 if (lpitem
->fState
& MF_GRAYED
)
1337 if (!(lpitem
->fState
& MF_HILITE
) )
1339 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1340 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1341 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1342 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1344 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1346 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1350 SelectObject (hdc
, hfontOld
);
1354 /***********************************************************************
1357 * Paint a popup menu.
1359 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1361 HBRUSH hPrevBrush
= 0;
1364 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1366 GetClientRect( hwnd
, &rect
);
1368 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1369 && (SelectObject( hdc
, hMenuFont
)))
1373 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1375 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1378 BOOL flat_menu
= FALSE
;
1379 ROSMENUINFO MenuInfo
;
1380 ROSMENUITEMINFO ItemInfo
;
1382 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1384 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1386 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1388 /* draw menu items */
1389 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1393 MenuInitRosMenuItemInfo(&ItemInfo
);
1395 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1397 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1399 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1400 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1404 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1408 SelectObject( hdc
, hPrevBrush
);
1413 /***********************************************************************
1416 * Paint a menu bar. Returns the height of the menu bar.
1417 * called from [windows/nonclient.c]
1419 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1424 HMENU hMenu
= GetMenu(hwnd
);
1426 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1428 return GetSystemMetrics(SM_CYMENU
);
1433 hfontOld
= SelectObject(hDC
, hMenuFont
);
1435 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1437 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1439 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1440 return lppop
.Height
;
1443 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1446 /***********************************************************************
1449 * Display a popup menu.
1451 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1452 INT x
, INT y
, INT xanchor
, INT yanchor
)
1454 ROSMENUINFO MenuInfo
;
1455 ROSMENUITEMINFO ItemInfo
;
1461 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1462 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1464 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1465 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1467 MenuInitRosMenuItemInfo(&ItemInfo
);
1468 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1470 ItemInfo
.fMask
|= MIIM_STATE
;
1471 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1472 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1474 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1475 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1478 /* store the owner for DrawItem */
1479 MenuInfo
.WndOwner
= hwndOwner
;
1480 MenuSetRosMenuInfo(&MenuInfo
);
1482 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1484 /* adjust popup menu pos so that it fits within the desktop */
1486 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1487 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1489 /* FIXME: should use item rect */
1492 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1493 info
.cbSize
= sizeof(info
);
1494 GetMonitorInfoW( monitor
, &info
);
1496 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1497 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1499 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1500 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1502 if( x
+ width
> info
.rcWork
.right
)
1504 if( xanchor
&& x
>= width
- xanchor
)
1505 x
-= width
- xanchor
;
1507 if( x
+ width
> info
.rcWork
.right
)
1508 x
= info
.rcWork
.right
- width
;
1510 if( x
< info
.rcWork
.left
) x
= info
.rcWork
.left
;
1512 if( y
+ height
> info
.rcWork
.bottom
)
1514 if( yanchor
&& y
>= height
+ yanchor
)
1515 y
-= height
+ yanchor
;
1517 if( y
+ height
> info
.rcWork
.bottom
)
1518 y
= info
.rcWork
.bottom
- height
;
1520 if( y
< info
.rcWork
.top
) y
= info
.rcWork
.top
;
1522 /* NOTE: In Windows, top menu popup is not owned. */
1523 MenuInfo
.Wnd
= CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW
, NULL
,
1524 WS_POPUP
, x
, y
, width
, height
,
1525 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1526 (LPVOID
) MenuInfo
.Self
);
1527 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1529 top_popup
= MenuInfo
.Wnd
;
1532 /* Display the window */
1534 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1535 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1536 UpdateWindow( MenuInfo
.Wnd
);
1540 /***********************************************************************
1543 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1544 BOOL sendMenuSelect
, HMENU topmenu
)
1546 ROSMENUITEMINFO ItemInfo
;
1547 ROSMENUINFO TopMenuInfo
;
1550 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1552 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1553 if (hmenu
->FocusedItem
== wIndex
) return;
1554 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1555 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1557 top_popup
= hmenu
->Wnd
;
1560 SelectObject( hdc
, hMenuFont
);
1562 MenuInitRosMenuItemInfo(&ItemInfo
);
1564 /* Clear previous highlighted item */
1565 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1567 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1569 ItemInfo
.fMask
|= MIIM_STATE
;
1570 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1571 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1573 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1574 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1578 /* Highlight new item (if any) */
1579 hmenu
->FocusedItem
= wIndex
;
1580 MenuSetRosMenuInfo(hmenu
);
1581 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1583 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1585 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1587 ItemInfo
.fMask
|= MIIM_STATE
;
1588 ItemInfo
.fState
|= MF_HILITE
;
1589 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1590 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1591 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1596 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1597 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1598 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1599 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1603 else if (sendMenuSelect
) {
1606 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1607 if (pos
!= NO_SELECTED_ITEM
)
1609 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1610 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1612 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1613 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1615 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1621 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1622 ReleaseDC(hmenu
->Wnd
, hdc
);
1625 /***********************************************************************
1628 * Moves currently selected item according to the Offset parameter.
1629 * If there is no selection then it should select the last item if
1630 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1632 static void FASTCALL
1633 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1636 ROSMENUITEMINFO ItemInfo
;
1639 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1641 /* Prevent looping */
1642 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1644 else if (Offset
< -1)
1646 else if (Offset
> 1)
1649 MenuInitRosMenuItemInfo(&ItemInfo
);
1651 OrigPos
= MenuInfo
->FocusedItem
;
1652 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1659 i
= MenuInfo
->FocusedItem
;
1666 /* Clip and wrap around */
1669 i
= MenuInfo
->MenuItemCount
- 1;
1671 else if (i
>= MenuInfo
->MenuItemCount
)
1675 /* If this is a good candidate; */
1676 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1677 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1679 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1680 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1683 } while (i
!= OrigPos
);
1686 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1689 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1691 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1697 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1698 SetWindowLongPtrA(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1702 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1703 return MA_NOACTIVATE
;
1708 BeginPaint(Wnd
, &ps
);
1709 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1714 case WM_PRINTCLIENT
:
1716 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1717 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1725 /* zero out global pointer in case resident popup window was destroyed. */
1726 if (Wnd
== top_popup
)
1735 if (0 == GetWindowLongPtrA(Wnd
, 0))
1737 OutputDebugStringA("no menu to display\n");
1742 SetWindowLongPtrA(Wnd
, 0, 0);
1746 case MM_SETMENUHANDLE
:
1747 SetWindowLongPtrA(Wnd
, 0, wParam
);
1750 case MM_GETMENUHANDLE
:
1752 return GetWindowLongPtrA(Wnd
, 0);
1755 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1761 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1763 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1769 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1770 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1774 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1775 return MA_NOACTIVATE
;
1780 BeginPaint(Wnd
, &ps
);
1781 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1786 case WM_PRINTCLIENT
:
1788 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1789 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1797 /* zero out global pointer in case resident popup window was destroyed. */
1798 if (Wnd
== top_popup
)
1807 if (0 == GetWindowLongPtrW(Wnd
, 0))
1809 OutputDebugStringA("no menu to display\n");
1814 SetWindowLongPtrW(Wnd
, 0, 0);
1818 case MM_SETMENUHANDLE
:
1819 SetWindowLongPtrW(Wnd
, 0, wParam
);
1822 case MM_GETMENUHANDLE
:
1824 return GetWindowLongPtrW(Wnd
, 0);
1827 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1833 /**********************************************************************
1834 * MENU_ParseResource
1836 * Parse a standard menu resource and add items to the menu.
1837 * Return a pointer to the end of the resource.
1839 * NOTE: flags is equivalent to the mtOption field
1841 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1850 flags
= GET_WORD(res
);
1852 /* remove MF_END flag before passing it to AppendMenu()! */
1853 end
= (flags
& MF_END
);
1854 if(end
) flags
^= MF_END
;
1856 res
+= sizeof(WORD
);
1857 if(!(flags
& MF_POPUP
))
1860 res
+= sizeof(WORD
);
1864 res
+= strlen(str
) + 1;
1866 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1867 if (flags
& MF_POPUP
)
1869 hSubMenu
= CreatePopupMenu();
1870 if(!hSubMenu
) return NULL
;
1871 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1874 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1876 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1878 else /* Not a popup */
1883 flags
= MF_SEPARATOR
;
1887 if (*(LPCWSTR
)str
== 0)
1888 flags
= MF_SEPARATOR
;
1891 if (flags
& MF_SEPARATOR
)
1893 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1894 flags
|= MF_GRAYED
| MF_DISABLED
;
1898 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1900 AppendMenuW(hMenu
, flags
, id
,
1901 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1908 /**********************************************************************
1909 * MENUEX_ParseResource
1911 * Parse an extended menu resource and add items to the menu.
1912 * Return a pointer to the end of the resource.
1914 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1920 mii
.cbSize
= sizeof(mii
);
1921 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
1922 mii
.fType
= GET_DWORD(res
);
1923 res
+= sizeof(DWORD
);
1924 mii
.fState
= GET_DWORD(res
);
1925 res
+= sizeof(DWORD
);
1926 mii
.wID
= GET_DWORD(res
);
1927 res
+= sizeof(DWORD
);
1928 resinfo
= GET_WORD(res
);
1929 res
+= sizeof(WORD
);
1930 /* Align the text on a word boundary. */
1931 res
+= (~((UINT_PTR
)res
- 1)) & 1;
1932 mii
.dwTypeData
= (LPWSTR
) res
;
1933 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1934 /* Align the following fields on a dword boundary. */
1935 res
+= (~((UINT_PTR
)res
- 1)) & 3;
1937 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
1938 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
1940 if (resinfo
& 1) { /* Pop-up? */
1941 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1942 res
+= sizeof(DWORD
);
1943 mii
.hSubMenu
= CreatePopupMenu();
1946 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1947 DestroyMenu(mii
.hSubMenu
);
1950 mii
.fMask
|= MIIM_SUBMENU
;
1951 mii
.fType
|= MF_POPUP
;
1952 mii
.wID
= (UINT
) mii
.hSubMenu
;
1954 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1956 mii
.fType
|= MF_SEPARATOR
;
1958 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1959 } while (!(resinfo
& MF_END
));
1964 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1966 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
1967 LRESULT Result
= (LRESULT
)hmenu
;
1968 MENUINFO menuinfo
= {0};
1969 MENUITEMINFOW info
= {0};
1971 // removing space for checkboxes from menu
1972 menuinfo
.cbSize
= sizeof(menuinfo
);
1973 menuinfo
.fMask
= MIM_STYLE
;
1974 GetMenuInfo(hmenu
, &menuinfo
);
1975 menuinfo
.dwStyle
|= MNS_NOCHECK
;
1976 SetMenuInfo(hmenu
, &menuinfo
);
1978 // adding bitmaps to menu items
1979 info
.cbSize
= sizeof(info
);
1980 info
.fMask
|= MIIM_BITMAP
;
1981 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
1982 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
1983 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
1984 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
1985 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
1986 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
1987 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
1988 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
1990 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1997 NONCLIENTMETRICSW ncm
;
1999 /* get the menu font */
2000 if(!hMenuFont
|| !hMenuFontBold
)
2002 ncm
.cbSize
= sizeof(ncm
);
2003 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2005 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2009 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2010 if(hMenuFont
== NULL
)
2012 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2016 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2017 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2018 if(hMenuFontBold
== NULL
)
2020 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2021 DeleteObject(hMenuFont
);
2035 DeleteObject(hMenuFont
);
2041 DeleteObject(hMenuFontBold
);
2042 hMenuFontBold
= NULL
;
2046 /***********************************************************************
2047 * DrawMenuBarTemp (USER32.@)
2051 * called by W98SE desk.cpl Control Panel Applet
2053 * Not 100% sure about the param names, but close.
2058 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2060 ROSMENUINFO MenuInfo
;
2061 ROSMENUITEMINFO ItemInfo
;
2063 HFONT FontOld
= NULL
;
2064 BOOL flat_menu
= FALSE
;
2066 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2070 Menu
= GetMenu(Wnd
);
2078 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2080 return GetSystemMetrics(SM_CYMENU
);
2083 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2085 FontOld
= SelectObject(DC
, Font
);
2087 if (0 == MenuInfo
.Height
)
2089 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2092 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2094 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2096 SelectObject(DC
, GetStockObject(DC_PEN
));
2097 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2098 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
2099 LineTo(DC
, Rect
->right
, Rect
->bottom
);
2101 if (0 == MenuInfo
.MenuItemCount
)
2103 SelectObject(DC
, FontOld
);
2104 return GetSystemMetrics(SM_CYMENU
);
2107 MenuInitRosMenuItemInfo(&ItemInfo
);
2108 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2110 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2112 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2113 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2116 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2118 SelectObject(DC
, FontOld
);
2120 return MenuInfo
.Height
;
2123 /***********************************************************************
2124 * MenuInitSysMenuPopup
2126 * Grey the appropriate items in System menu.
2129 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2137 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2138 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2139 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2140 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2141 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2142 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2143 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2144 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2145 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2146 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2147 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2149 /* The menu item must keep its state if it's disabled */
2152 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2155 /* Set default menu item */
2156 if(Style
& WS_MINIMIZE
)
2158 DefItem
= SC_RESTORE
;
2162 if(HitTest
== HTCAPTION
)
2164 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2172 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2173 mii
.fMask
|= MIIM_STATE
;
2174 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2175 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2180 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2183 /***********************************************************************
2186 * Display the sub-menu of the selected item of this menu.
2187 * Return the handle of the submenu, or menu if no submenu to display.
2189 static HMENU FASTCALL
2190 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2192 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2194 ROSMENUITEMINFO ItemInfo
;
2195 ROSMENUINFO SubMenuInfo
;
2199 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2201 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2203 return MenuInfo
->Self
;
2206 MenuInitRosMenuItemInfo(&ItemInfo
);
2207 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2209 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2210 return MenuInfo
->Self
;
2212 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2214 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2215 return MenuInfo
->Self
;
2218 /* message must be sent before using item,
2219 because nearly everything may be changed by the application ! */
2221 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2222 if (0 == (Flags
& TPM_NONOTIFY
))
2224 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2225 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2228 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2230 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2231 return MenuInfo
->Self
;
2233 Rect
= ItemInfo
.Rect
;
2235 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2236 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2238 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2240 Dc
= GetDC(MenuInfo
->Wnd
);
2244 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2247 SelectObject(Dc
, hMenuFont
);
2248 ItemInfo
.fMask
|= MIIM_STATE
;
2249 ItemInfo
.fState
|= MF_HILITE
;
2250 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2251 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2252 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2253 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2256 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2257 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2259 ItemInfo
.Rect
= Rect
;
2262 ItemInfo
.fMask
|= MIIM_STATE
;
2263 ItemInfo
.fState
|= MF_MOUSESELECT
;
2264 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2266 if (IS_SYSTEM_MENU(MenuInfo
))
2268 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2269 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2271 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2272 Rect
.top
= Rect
.bottom
;
2273 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2274 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2278 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2279 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2281 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2282 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2283 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2284 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2285 - GetSystemMetrics(SM_CYBORDER
);
2289 Rect
.left
+= ItemInfo
.Rect
.left
;
2290 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2291 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2292 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2296 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2297 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2298 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2300 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2303 Ret
= ItemInfo
.hSubMenu
;
2304 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2309 /***********************************************************************
2312 * Hide the sub-popup menus of this menu.
2314 static void FASTCALL
2315 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2317 ROSMENUINFO SubMenuInfo
;
2318 ROSMENUITEMINFO ItemInfo
;
2320 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2322 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2324 MenuInitRosMenuItemInfo(&ItemInfo
);
2325 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2326 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2327 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2328 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2330 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2333 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2334 ItemInfo
.fMask
|= MIIM_STATE
;
2335 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2336 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2338 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2339 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2340 DestroyWindow(SubMenuInfo
.Wnd
);
2341 SubMenuInfo
.Wnd
= NULL
;
2342 MenuSetRosMenuInfo(&SubMenuInfo
);
2347 /***********************************************************************
2348 * MenuSwitchTracking
2350 * Helper function for menu navigation routines.
2352 static void FASTCALL
2353 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2355 ROSMENUINFO TopMenuInfo
;
2357 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2359 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2360 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2361 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2363 /* both are top level menus (system and menu-bar) */
2364 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2365 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2366 Mt
->TopMenu
= PtMenuInfo
->Self
;
2370 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2373 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2376 /***********************************************************************
2377 * MenuExecFocusedItem
2379 * Execute a menu item (for instance when user pressed Enter).
2380 * Return the wID of the executed item. Otherwise, -1 indicating
2381 * that no menu item was executed, -2 if a popup is shown;
2382 * Have to receive the flags for the TrackPopupMenu options to avoid
2383 * sending unwanted message.
2387 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2389 ROSMENUITEMINFO ItemInfo
;
2392 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2394 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2399 MenuInitRosMenuItemInfo(&ItemInfo
);
2400 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2402 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2406 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2408 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2410 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2411 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2413 /* If TPM_RETURNCMD is set you return the id, but
2414 do not send a message to the owner */
2415 if (0 == (Flags
& TPM_RETURNCMD
))
2417 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2419 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2420 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2424 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2425 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2426 MenuInfo
->FocusedItem
,
2427 (LPARAM
)MenuInfo
->Self
);
2429 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2433 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2439 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2446 /***********************************************************************
2449 * Return TRUE if we can go on with menu tracking.
2451 static BOOL FASTCALL
2452 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2455 ROSMENUINFO MenuInfo
;
2456 ROSMENUITEMINFO Item
;
2458 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2462 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2466 if (IS_SYSTEM_MENU(&MenuInfo
))
2472 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2474 MenuInitRosMenuItemInfo(&Item
);
2475 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2477 MenuCleanupRosMenuItemInfo(&Item
);
2481 if (!(Item
.fType
& MF_SEPARATOR
) &&
2482 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2484 if (MenuInfo
.FocusedItem
!= Index
)
2486 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2489 /* If the popup menu is not already "popped" */
2490 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2492 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2496 MenuCleanupRosMenuItemInfo(&Item
);
2501 /* else the click was on the menu bar, finish the tracking */
2506 /***********************************************************************
2509 * Return the value of MenuExecFocusedItem if
2510 * the selected item was not a popup. Else open the popup.
2511 * A -1 return value indicates that we go on with menu tracking.
2515 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2518 ROSMENUINFO MenuInfo
;
2519 ROSMENUITEMINFO ItemInfo
;
2521 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2526 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2531 if (! IS_SYSTEM_MENU(&MenuInfo
))
2533 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2535 MenuInitRosMenuItemInfo(&ItemInfo
);
2536 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2537 MenuInfo
.FocusedItem
== Id
)
2539 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2541 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2542 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2543 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2545 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2547 /* If we are dealing with the top-level menu */
2548 /* and this is a click on an already "popped" item: */
2549 /* Stop the menu tracking and close the opened submenus */
2550 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2552 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2556 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2557 MenuInfo
.TimeToHide
= TRUE
;
2558 MenuSetRosMenuInfo(&MenuInfo
);
2564 /***********************************************************************
2567 * Walks menu chain trying to find a menu pt maps to.
2569 static HMENU FASTCALL
2570 MenuPtMenu(HMENU Menu
, POINT Pt
)
2572 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2573 ROSMENUINFO MenuInfo
;
2574 ROSMENUITEMINFO ItemInfo
;
2578 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2583 /* try subpopup first (if any) */
2584 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2586 MenuInitRosMenuItemInfo(&ItemInfo
);
2587 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2588 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2589 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2591 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2594 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2598 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2601 /* check the current window (avoiding WM_HITTEST) */
2602 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2603 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2605 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2610 else if (HTSYSMENU
== Ht
)
2612 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2614 else if (HTMENU
== Ht
)
2616 Ret
= GetMenu(MenuInfo
.Wnd
);
2622 /***********************************************************************
2625 * Return TRUE if we can go on with menu tracking.
2627 static BOOL FASTCALL
2628 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2631 ROSMENUINFO MenuInfo
;
2632 ROSMENUITEMINFO ItemInfo
;
2636 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2640 if (IS_SYSTEM_MENU(&MenuInfo
))
2646 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2651 Index
= NO_SELECTED_ITEM
;
2654 if (NO_SELECTED_ITEM
== Index
)
2656 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2657 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2659 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2663 else if (MenuInfo
.FocusedItem
!= Index
)
2665 MenuInitRosMenuItemInfo(&ItemInfo
);
2666 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2667 !(ItemInfo
.fType
& MF_SEPARATOR
))
2669 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2670 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2671 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2673 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2679 /******************************************************************************
2681 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2683 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2686 PROSMENUITEMINFO MenuItems
;
2688 i
= MenuInfo
->FocusedItem
;
2689 if (NO_SELECTED_ITEM
== i
)
2694 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2696 return NO_SELECTED_ITEM
;
2699 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2701 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2707 return NO_SELECTED_ITEM
;
2710 /******************************************************************************
2712 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2714 static UINT FASTCALL
2715 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2718 PROSMENUITEMINFO MenuItems
;
2720 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2722 return NO_SELECTED_ITEM
;
2725 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2727 return NO_SELECTED_ITEM
;
2730 /* Find the start of the column */
2732 for (i
= MenuInfo
->FocusedItem
;
2733 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2741 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2742 return NO_SELECTED_ITEM
;
2745 for (--i
; 0 != i
; --i
)
2747 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2753 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2754 TRACE("ret %d.\n", i
);
2759 /***********************************************************************
2762 * Return the handle of the selected sub-popup menu (if any).
2764 static HMENU FASTCALL
2765 MenuGetSubPopup(HMENU Menu
)
2767 ROSMENUINFO MenuInfo
;
2768 ROSMENUITEMINFO ItemInfo
;
2770 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2771 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2776 MenuInitRosMenuItemInfo(&ItemInfo
);
2777 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2779 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2782 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2784 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2785 return ItemInfo
.hSubMenu
;
2788 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2792 /***********************************************************************
2795 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2797 static LRESULT FASTCALL
2798 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2800 ROSMENUINFO TopMenuInfo
;
2801 ROSMENUINFO MenuInfo
;
2803 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2805 return (LRESULT
) FALSE
;
2808 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2809 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2811 MDINEXTMENU NextMenu
;
2816 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2817 NextMenu
.hmenuNext
= NULL
;
2818 NextMenu
.hwndNext
= NULL
;
2819 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2821 TRACE("%p [%p] -> %p [%p]\n",
2822 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2824 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2826 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2827 NewWnd
= Mt
->OwnerWnd
;
2828 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2830 /* switch to the menu bar */
2832 if (0 != (Style
& WS_CHILD
)
2833 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2840 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2844 Id
= MenuInfo
.MenuItemCount
- 1;
2847 else if (0 != (Style
& WS_SYSMENU
))
2849 /* switch to the system menu */
2850 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2857 else /* application returned a new menu to switch to */
2859 NewMenu
= NextMenu
.hmenuNext
;
2860 NewWnd
= NextMenu
.hwndNext
;
2862 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2864 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2866 if (0 != (Style
& WS_SYSMENU
)
2867 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2869 /* get the real system menu */
2870 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2872 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2874 /* FIXME: Not sure what to do here;
2875 * perhaps try to track NewMenu as a popup? */
2877 WARN(" -- got confused.\n");
2887 if (NewMenu
!= Mt
->TopMenu
)
2889 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2891 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2893 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2897 if (NewWnd
!= Mt
->OwnerWnd
)
2899 Mt
->OwnerWnd
= NewWnd
;
2900 SetCapture(Mt
->OwnerWnd
);
2901 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2904 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2905 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2907 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2916 /***********************************************************************
2919 * The idea is not to show the popup if the next input message is
2920 * going to hide it anyway.
2922 static BOOL FASTCALL
2923 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2927 Msg
.hwnd
= Mt
->OwnerWnd
;
2929 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2930 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2935 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2936 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2938 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2939 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2940 if (WM_KEYDOWN
== Msg
.message
2941 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2943 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2950 /* failures go through this */
2951 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2956 /***********************************************************************
2959 * Handle a VK_ESCAPE key event in a menu.
2961 static BOOL FASTCALL
2962 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2964 BOOL EndMenu
= TRUE
;
2965 ROSMENUINFO MenuInfo
;
2966 HMENU MenuTmp
, MenuPrev
;
2968 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2970 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2971 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2973 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2975 /* close topmost popup */
2976 while (MenuTmp
!= Mt
->CurrentMenu
)
2979 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2982 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2984 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
2986 Mt
->CurrentMenu
= MenuPrev
;
2994 /***********************************************************************
2997 * Handle a VK_LEFT key event in a menu.
2999 static void FASTCALL
3000 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3002 ROSMENUINFO MenuInfo
;
3003 ROSMENUINFO TopMenuInfo
;
3004 ROSMENUINFO PrevMenuInfo
;
3005 HMENU MenuTmp
, MenuPrev
;
3008 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3010 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3015 /* Try to move 1 column left (if possible) */
3016 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3018 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3020 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3025 /* close topmost popup */
3026 while (MenuTmp
!= Mt
->CurrentMenu
)
3029 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3032 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3036 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
3037 Mt
->CurrentMenu
= MenuPrev
;
3039 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3043 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3045 /* move menu bar selection if no more popups are left */
3047 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
3049 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3052 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3054 /* A sublevel menu was displayed - display the next one
3055 * unless there is another displacement coming up */
3057 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3058 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3060 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3067 /***********************************************************************
3070 * Handle a VK_RIGHT key event in a menu.
3072 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3075 ROSMENUINFO MenuInfo
;
3076 ROSMENUINFO CurrentMenuInfo
;
3079 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3080 Mt
->CurrentMenu
, Mt
->TopMenu
);
3082 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3083 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3085 /* If already displaying a popup, try to display sub-popup */
3087 hmenutmp
= Mt
->CurrentMenu
;
3088 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3090 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3093 /* if subpopup was displayed then we are done */
3094 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3097 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3102 /* Check to see if there's another column */
3103 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3105 TRACE("Going to %d.\n", NextCol
);
3106 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3108 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3113 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3115 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3117 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3118 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3125 /* try to move to the next item */
3126 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
))
3127 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3129 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3131 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3132 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3134 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3141 /***********************************************************************
3144 * Menu tracking code.
3146 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3147 HWND hwnd
, const RECT
*lprect
)
3150 ROSMENUINFO MenuInfo
;
3151 ROSMENUITEMINFO ItemInfo
;
3153 INT executedMenuId
= -1;
3155 BOOL enterIdleSent
= FALSE
;
3158 mt
.CurrentMenu
= hmenu
;
3164 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3165 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3166 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3170 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3175 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3180 if (wFlags
& TPM_BUTTONDOWN
)
3182 /* Get the result in order to start the tracking or not */
3183 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3184 fEndMenu
= !fRemove
;
3187 SetCapture(mt
.OwnerWnd
);
3188 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, mt
.OwnerWnd
);
3190 ERR("MenuTrackMenu 1\n");
3193 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, VALIDATE_TYPE_MENU
);
3194 if (!menu
) /* sometimes happens if I do a window manager close */
3197 /* we have to keep the message in the queue until it's
3198 * clear that menu loop is not over yet. */
3202 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3204 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3205 /* remove the message from the queue */
3206 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3212 HWND win
= (wFlags
& TPM_ENTERIDLEEX
) && (MenuInfo
.Flags
& MF_POPUP
) ? MenuInfo
.Wnd
: NULL
;
3213 enterIdleSent
= TRUE
;
3214 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3220 /* check if EndMenu() tried to cancel us, by posting this message */
3221 if (msg
.message
== WM_CANCELMODE
)
3223 /* we are now out of the loop */
3226 /* remove the message from the queue */
3227 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3229 /* break out of internal loop, ala ESCAPE */
3233 TranslateMessage( &msg
);
3236 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3237 enterIdleSent
=FALSE
;
3240 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3243 * Use the mouse coordinates in lParam instead of those in the MSG
3244 * struct to properly handle synthetic messages. They are already
3245 * in screen coordinates.
3247 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3248 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3250 /* Find a menu for this mouse event */
3251 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3255 /* no WM_NC... messages in captured state */
3257 case WM_RBUTTONDBLCLK
:
3258 case WM_RBUTTONDOWN
:
3259 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3261 case WM_LBUTTONDBLCLK
:
3262 case WM_LBUTTONDOWN
:
3263 /* If the message belongs to the menu, removes it from the queue */
3264 /* Else, end menu tracking */
3265 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3266 fEndMenu
= !fRemove
;
3270 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3273 /* Check if a menu was selected by the mouse */
3276 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3278 /* End the loop if executedMenuId is an item ID */
3279 /* or if the job was done (executedMenuId = 0). */
3280 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3284 /* No menu was selected by the mouse */
3285 /* if the function was called by TrackPopupMenu, continue
3286 with the menu tracking. If not, stop it */
3287 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3293 fEndMenu
|= !MenuMouseMove(&mt
, hmenu
, wFlags
);
3296 } /* switch(Msg.message) - mouse */
3298 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3300 fRemove
= TRUE
; /* Keyboard messages are always removed */
3312 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3314 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3316 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3317 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3322 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3323 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3325 if (!(MenuInfo
.Flags
& MF_POPUP
))
3327 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3329 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
,
3333 else /* otherwise try to move selection */
3335 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3336 VK_DOWN
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3342 MenuKeyLeft(&mt
, wFlags
);
3346 MenuKeyRight(&mt
, wFlags
);
3350 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3356 hi
.cbSize
= sizeof(HELPINFO
);
3357 hi
.iContextType
= HELPINFO_MENUITEM
;
3358 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3360 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
) hi
.iCtrlId
= 0;
3363 MenuInitRosMenuItemInfo(&ItemInfo
);
3364 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3365 MenuInfo
.FocusedItem
,
3368 hi
.iCtrlId
= ItemInfo
.wID
;
3374 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3377 hi
.hItemHandle
= hmenu
;
3378 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3379 hi
.MousePos
= msg
.pt
;
3380 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3387 break; /* WM_KEYDOWN */
3394 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3395 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3397 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3398 fEndMenu
= (executedMenuId
!= -2);
3402 /* Hack to avoid control chars. */
3403 /* We will find a better way real soon... */
3404 if (msg
.wParam
< 32) break;
3406 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3407 LOWORD(msg
.wParam
), FALSE
);
3408 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3409 else if (pos
== (UINT
)-1) MessageBeep(0);
3412 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3414 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3415 fEndMenu
= (executedMenuId
!= -2);
3419 } /* switch(msg.message) - kbd */
3423 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3424 DispatchMessageW( &msg
);
3428 if (!fEndMenu
) fRemove
= TRUE
;
3430 /* finally remove message from the queue */
3432 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3433 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3434 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3437 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3438 SetCapture(NULL
); /* release the capture */
3440 /* If dropdown is still painted and the close box is clicked on
3441 then the menu will be destroyed as part of the DispatchMessage above.
3442 This will then invalidate the menu handle in mt.hTopMenu. We should
3443 check for this first. */
3444 if( IsMenu( mt
.TopMenu
) )
3446 if (IsWindow(mt
.OwnerWnd
))
3448 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3450 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3452 if (MenuInfo
.Flags
& MF_POPUP
)
3454 DestroyWindow(MenuInfo
.Wnd
);
3455 MenuInfo
.Wnd
= NULL
;
3457 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3458 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3459 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3462 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3465 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3468 /* Reset the variable for hiding menu */
3469 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3471 MenuInfo
.TimeToHide
= FALSE
;
3472 MenuSetRosMenuInfo(&MenuInfo
);
3476 /* The return value is only used by TrackPopupMenu */
3477 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3478 if (executedMenuId
== -1) executedMenuId
= 0;
3479 return executedMenuId
;
3482 /***********************************************************************
3485 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3487 ROSMENUINFO MenuInfo
;
3489 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3493 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3494 if (!(wFlags
& TPM_NONOTIFY
))
3495 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3497 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3499 if (!(wFlags
& TPM_NONOTIFY
))
3501 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3503 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
3505 if (!MenuInfo
.Height
)
3507 /* app changed/recreated menu bar entries in WM_INITMENU
3508 Recalculate menu sizes else clicks will not work */
3509 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3510 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3513 /* This makes the menus of applications built with Delphi work.
3514 * It also enables menus to be displayed in more than one window,
3515 * but there are some bugs left that need to be fixed in this case.
3517 if(MenuInfo
.Self
== hMenu
)
3519 MenuInfo
.Wnd
= hWnd
;
3520 MenuSetRosMenuInfo(&MenuInfo
);
3526 /***********************************************************************
3529 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
)
3531 TRACE("hwnd=%p\n", hWnd
);
3533 SendMessageW( hWnd
, WM_EXITMENULOOP
, 0, 0 );
3539 /***********************************************************************
3540 * MenuTrackMouseMenuBar
3542 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3544 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3546 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3547 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3549 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3553 /* map point to parent client coordinates */
3554 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3555 if (Parent
!= GetDesktopWindow())
3557 ScreenToClient(Parent
, &pt
);
3560 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3561 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3562 MenuExitTracking(hWnd
);
3567 /***********************************************************************
3568 * MenuTrackKbdMenuBar
3570 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3572 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3574 UINT uItem
= NO_SELECTED_ITEM
;
3576 ROSMENUINFO MenuInfo
;
3577 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3579 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3581 /* find window that has a menu */
3583 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3584 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3585 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3587 /* check if we have to track a system menu */
3589 hTrackMenu
= GetMenu( hwnd
);
3590 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3592 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3593 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3595 wParam
|= HTSYSMENU
; /* prevent item lookup */
3598 if (!IsMenu( hTrackMenu
)) return;
3600 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3602 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3607 if( wChar
&& wChar
!= ' ' )
3609 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3610 if ( uItem
>= (UINT
)(-2) )
3612 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3613 /* schedule end of menu tracking */
3614 wFlags
|= TF_ENDMENU
;
3619 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3621 if (wParam
& HTSYSMENU
)
3623 /* prevent sysmenu activation for managed windows on Alt down/up */
3624 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3625 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3629 if( uItem
== NO_SELECTED_ITEM
)
3630 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3632 PostMessageW( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3636 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3637 MenuExitTracking( hwnd
);
3643 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3644 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3646 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3648 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3649 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3650 * MFT_STRING is replaced by MIIM_STRING.
3651 * (So, I guess we should use MIIM_STRING only for strings?)
3653 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3655 * Based on wine, SetMenuItemInfo_common:
3656 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3657 * it will result in a error.
3658 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3659 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3666 LPMENUITEMINFOW mii
,
3673 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3675 if(Flags
& MF_BITMAP
)
3677 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3678 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3680 if (Flags
& MF_HELP
)
3682 /* increase ident */
3683 mii
->fType
|= MF_HELP
;
3686 else if(Flags
& MF_OWNERDRAW
)
3688 mii
->fType
|= MFT_OWNERDRAW
;
3689 mii
->fMask
|= MIIM_DATA
;
3690 mii
->dwItemData
= (DWORD
) NewItem
;
3692 else if (Flags
& MF_SEPARATOR
)
3694 mii
->fType
|= MFT_SEPARATOR
;
3695 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3696 Flags
|= MF_GRAYED
|MF_DISABLED
;
3698 else /* Default action MF_STRING. */
3700 /* Item beginning with a backspace is a help item */
3701 if (NewItem
!= NULL
)
3705 if (*NewItem
== '\b')
3707 mii
->fType
|= MF_HELP
;
3713 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3714 if (*NewItemA
== '\b')
3716 mii
->fType
|= MF_HELP
;
3718 NewItem
= (LPCWSTR
) NewItemA
;
3722 if (Flags
& MF_HELP
)
3723 mii
->fType
|= MF_HELP
;
3724 mii
->fMask
|= MIIM_STRING
;
3725 mii
->fType
|= MFT_STRING
; /* Zero */
3726 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3728 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3730 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3734 mii
->fType
|= MFT_SEPARATOR
;
3735 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3736 Flags
|= MF_GRAYED
|MF_DISABLED
;
3740 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3742 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3745 if(Flags
& MF_MENUBREAK
)
3747 mii
->fType
|= MFT_MENUBREAK
;
3749 else if(Flags
& MF_MENUBARBREAK
)
3751 mii
->fType
|= MFT_MENUBARBREAK
;
3754 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3756 if (Flags
& MF_GRAYED
)
3757 mii
->fState
|= MF_GRAYED
;
3759 if (Flags
& MF_DISABLED
)
3760 mii
->fState
|= MF_DISABLED
;
3762 mii
->fMask
|= MIIM_STATE
;
3764 else if (Flags
& MF_HILITE
)
3766 mii
->fState
|= MF_HILITE
;
3767 mii
->fMask
|= MIIM_STATE
;
3769 else /* default state */
3771 mii
->fState
|= MFS_ENABLED
;
3772 mii
->fMask
|= MIIM_STATE
;
3775 if(Flags
& MF_POPUP
)
3777 mii
->fType
|= MF_POPUP
;
3778 mii
->fMask
|= MIIM_SUBMENU
;
3779 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3783 mii
->fMask
|= MIIM_ID
;
3784 mii
->wID
= (UINT
)IDNewItem
;
3790 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3792 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3795 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3797 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3798 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3799 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3800 (LPCWSTR
)&Common
->MenuName
);
3802 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3806 /* FUNCTIONS *****************************************************************/
3809 MenuIsStringItem(ULONG TypeData)
3811 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3819 AppendMenuA(HMENU hMenu
,
3821 UINT_PTR uIDNewItem
,
3824 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3833 AppendMenuW(HMENU hMenu
,
3835 UINT_PTR uIDNewItem
,
3838 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3847 CheckMenuItem(HMENU hmenu
,
3851 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3856 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3859 PROSMENUITEMINFO Items
= NULL
;
3860 UINT cChecked
, cUnchecked
;
3864 if(idFirst
> idLast
)
3867 ItemCount
= GetMenuItemCount(hMenu
);
3869 //mi.cbSize = sizeof(ROSMENUINFO);
3870 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3873 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3875 ERR("MenuGetAllRosMenuItemInfo failed\n");
3879 cChecked
= cUnchecked
= 0;
3881 for (i
= 0 ; i
< ItemCount
; i
++)
3884 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3885 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3887 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3889 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3892 if (uFlags
& MF_BYPOSITION
)
3894 if (i
< idFirst
|| i
> idLast
)
3909 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3912 if (Items
[i
].wID
== idCheck
)
3926 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
3929 Items
[i
].fType
|= MFT_RADIOCHECK
;
3930 Items
[i
].fState
|= MFS_CHECKED
;
3934 Items
[i
].fState
&= ~MFS_CHECKED
;
3937 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
3939 ERR("MenuSetRosMenuItemInfo failed\n");
3944 HeapFree(GetProcessHeap(), 0, Items
);
3946 *pChecked
+= cChecked
;
3947 *pUnchecked
+= cUnchecked
;
3949 if (cChecked
|| cUnchecked
)
3959 CheckMenuRadioItem(HMENU hmenu
,
3966 UINT cUnchecked
= 0;
3967 UINT cMenuChanged
= 0;
3969 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
3972 if (cMenuChanged
> 1)
3979 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
3982 return (cChecked
!= 0);
3993 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4001 CreatePopupMenu(VOID
)
4004 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4012 DrawMenuBar(HWND hWnd
)
4014 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4015 ROSMENUINFO MenuInfo
;
4017 hMenu
= GetMenu(hWnd
);
4020 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4021 MenuInfo
.Height
= 0; // make sure to recalc size
4022 MenuSetRosMenuInfo(&MenuInfo
);
4023 /* The wine method doesn't work and I suspect it's more effort
4024 then hackfix solution
4025 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4026 SWP_NOZORDER | SWP_FRAMECHANGED );
4029 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4038 EnableMenuItem(HMENU hMenu
,
4042 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4052 guii
.cbSize
= sizeof(GUITHREADINFO
);
4053 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4055 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4067 PWND Wnd
= ValidateHwnd(hWnd
);
4072 return (HMENU
)Wnd
->IDMenu
;
4080 GetMenuCheckMarkDimensions(VOID
)
4082 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4083 GetSystemMetrics(SM_CYMENUCHECK
)));
4091 GetMenuDefaultItem(HMENU hMenu
,
4095 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4103 GetMenuInfo(HMENU hmenu
,
4109 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4112 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4113 mi
.cbSize
= sizeof(MENUINFO
);
4114 mi
.fMask
= lpcmi
->fMask
;
4116 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4118 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4127 GetMenuItemCount(HMENU Menu
)
4129 ROSMENUINFO MenuInfo
;
4131 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4139 GetMenuItemID(HMENU hMenu
,
4142 ROSMENUITEMINFO mii
;
4144 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4145 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4147 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4152 if (NULL
!= mii
.hSubMenu
)
4173 LPMENUITEMINFOA mii
)
4179 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4180 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4182 SetLastError(ERROR_INVALID_PARAMETER
);
4186 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4188 /* No text requested, just pass on */
4189 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4192 AnsiBuffer
= mii
->dwTypeData
;
4193 Count
= miiW
.cch
= mii
->cch
;
4194 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4195 miiW
.dwTypeData
= 0;
4199 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4200 miiW
.cch
* sizeof(WCHAR
));
4201 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4202 miiW
.dwTypeData
[0] = 0;
4205 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4207 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4211 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4213 if (!AnsiBuffer
|| !Count
)
4215 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4216 mii
->dwTypeData
= AnsiBuffer
;
4217 mii
->cch
= miiW
.cch
;
4221 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4225 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4229 if (Count
> miiW
.cch
)
4231 AnsiBuffer
[miiW
.cch
] = 0;
4233 mii
->cch
= mii
->cch
;
4241 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4242 mii
->dwTypeData
= AnsiBuffer
;
4256 LPMENUITEMINFOW mii
)
4262 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4263 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4265 SetLastError(ERROR_INVALID_PARAMETER
);
4269 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4271 /* No text requested, just pass on */
4272 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4275 String
= mii
->dwTypeData
;
4277 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4278 miiW
.dwTypeData
= 0;
4282 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4283 miiW
.cch
* sizeof(WCHAR
));
4284 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4285 miiW
.dwTypeData
[0] = 0;
4288 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4290 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4294 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4296 if (!String
|| !Count
)
4298 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4299 mii
->dwTypeData
= String
; // may not be zero.
4300 mii
->cch
= miiW
.cch
;
4304 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4306 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4309 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4310 mii
->dwTypeData
= String
;
4311 mii
->cch
= strlenW(String
);
4326 ROSMENUINFO MenuInfo
;
4327 ROSMENUITEMINFO mii
;
4328 memset( &mii
, 0, sizeof(mii
) );
4329 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4330 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4333 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4338 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4342 nSubItems
= MenuInfo
.MenuItemCount
;
4344 /* FIXME - ported from wine, does that work (0xff)? */
4345 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4346 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4348 return (UINT
)-1; /* Invalid submenu */
4351 /* FIXME - ported from wine, does that work? */
4352 return (mii
.fType
| mii
.fState
);
4372 memset( &mii
, 0, sizeof(mii
) );
4373 mii
.dwTypeData
= lpString
;
4374 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4375 mii
.fType
= MFT_STRING
;
4376 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4377 mii
.cch
= nMaxCount
;
4379 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4399 memset( &miiW
, 0, sizeof(miiW
) );
4400 miiW
.dwTypeData
= lpString
;
4401 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4402 miiW
.fType
= MFT_STRING
;
4403 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4404 miiW
.cch
= nMaxCount
;
4406 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4424 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4425 mi
.fMask
= MIIM_SUBMENU
;
4427 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4429 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4446 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4448 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4461 UINT_PTR uIDNewItem
,
4465 memset( &mii
, 0, sizeof(mii
) );
4466 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4467 mii
.fMask
= MIIM_FTYPE
;
4469 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4472 (LPCWSTR
) lpNewItem
,
4475 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4489 LPCMENUITEMINFOA lpmii
)
4492 UNICODE_STRING MenuText
;
4494 BOOL CleanHeap
= FALSE
;
4497 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4498 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4500 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4502 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4504 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4507 /* copy the text string */
4508 if (((mi
.fMask
& MIIM_STRING
) ||
4509 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4510 && mi
.dwTypeData
!= NULL
)
4512 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4513 if (!NT_SUCCESS (Status
))
4515 SetLastError (RtlNtStatusToDosError(Status
));
4518 mi
.dwTypeData
= MenuText
.Buffer
;
4519 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4522 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4524 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4539 LPCMENUITEMINFOW lpmii
)
4542 UNICODE_STRING MenuText
;
4545 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4546 if a bad user passes bad data, we crash his process instead of the
4549 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4550 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4552 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4554 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4556 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4559 /* copy the text string */
4560 if (((mi
.fMask
& MIIM_STRING
) ||
4561 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4562 && mi
.dwTypeData
!= NULL
)
4564 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4565 mi
.dwTypeData
= MenuText
.Buffer
;
4566 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4568 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4583 UINT_PTR uIDNewItem
,
4587 memset( &mii
, 0, sizeof(mii
) );
4588 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4589 mii
.fMask
= MIIM_FTYPE
;
4591 MenuSetItemData( &mii
,
4597 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4609 if (ValidateHandle(Menu
, VALIDATE_TYPE_MENU
)) return TRUE
;
4618 LoadMenuA(HINSTANCE hInstance
,
4621 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4622 if (Resource
== NULL
)
4626 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4634 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4636 return(LoadMenuIndirectW(lpMenuTemplate
));
4644 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4647 WORD version
, offset
;
4648 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4650 version
= GET_WORD(p
);
4655 case 0: /* standard format is version of 0 */
4656 offset
= GET_WORD(p
);
4657 p
+= sizeof(WORD
) + offset
;
4658 if (!(hMenu
= CreateMenu())) return 0;
4659 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4665 case 1: /* extended format is version of 1 */
4666 offset
= GET_WORD(p
);
4667 p
+= sizeof(WORD
) + offset
;
4668 if (!(hMenu
= CreateMenu())) return 0;
4669 if (!MENUEX_ParseResource(p
, hMenu
))
4671 DestroyMenu( hMenu
);
4676 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4686 LoadMenuW(HINSTANCE hInstance
,
4689 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4690 if (Resource
== NULL
)
4694 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4708 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4721 UINT_PTR uIDNewItem
,
4725 ROSMENUITEMINFO rmii
;
4727 memset( &mii
, 0, sizeof(mii
) );
4728 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4729 mii
.fMask
= MIIM_FTYPE
;
4731 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4735 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4737 MenuInitRosMenuItemInfo( &rmii
);
4739 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4741 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4742 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4744 MenuCleanupRosMenuItemInfo( &rmii
);
4746 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4749 (LPCWSTR
) lpNewItem
,
4752 return SetMenuItemInfoA( hMnu
,
4754 (BOOL
)(MF_BYPOSITION
& uFlags
),
4768 UINT_PTR uIDNewItem
,
4772 ROSMENUITEMINFO rmii
;
4774 memset ( &mii
, 0, sizeof(mii
) );
4775 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4776 mii
.fMask
= MIIM_FTYPE
;
4778 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4780 mi
.Height
= 0; // Force size recalculation.
4782 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4784 MenuInitRosMenuItemInfo( &rmii
);
4786 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4788 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4789 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4791 MenuCleanupRosMenuItemInfo( &rmii
);
4793 /* Init new data for this menu item */
4794 MenuSetItemData( &mii
,
4800 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4801 return SetMenuItemInfoW( hMnu
,
4803 (BOOL
)(MF_BYPOSITION
& uFlags
),
4815 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4831 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4833 SetLastError(ERROR_INVALID_PARAMETER
);
4837 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4838 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4851 HBITMAP hBitmapUnchecked
,
4852 HBITMAP hBitmapChecked
)
4854 ROSMENUITEMINFO uItem
;
4855 memset ( &uItem
, 0, sizeof(uItem
) );
4856 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4858 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4859 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4861 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4863 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4865 else /* Install new bitmaps */
4867 uItem
.hbmpChecked
= hBitmapChecked
;
4868 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4869 uItem
.fState
|= MF_USECHECKBITMAPS
;
4871 return NtUserMenuItemInfo(hMenu
, uPosition
,
4872 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4885 LPCMENUITEMINFOA lpmii
)
4887 MENUITEMINFOW MenuItemInfoW
;
4888 UNICODE_STRING UnicodeString
;
4890 ULONG Result
= FALSE
;
4892 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4894 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4896 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4897 MenuItemInfoW
.hbmpItem
= NULL
;
4900 * MIIM_STRING == good
4901 * MIIM_TYPE & MFT_STRING == good
4902 * MIIM_STRING & MFT_STRING == good
4903 * MIIM_STRING & MFT_OWNERSRAW == good
4905 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4906 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4907 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4908 && MenuItemInfoW
.dwTypeData
!= NULL
)
4910 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
4911 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
4912 (LPSTR
)MenuItemInfoW
.dwTypeData
);
4913 if (!NT_SUCCESS (Status
))
4915 SetLastError (RtlNtStatusToDosError(Status
));
4918 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
4919 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4923 UnicodeString
.Buffer
= NULL
;
4926 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
4927 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
4929 if (UnicodeString
.Buffer
!= NULL
)
4931 RtlFreeUnicodeString(&UnicodeString
);
4947 LPCMENUITEMINFOW lpmii
)
4949 MENUITEMINFOW MenuItemInfoW
;
4952 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4954 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4956 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4957 MenuItemInfoW
.hbmpItem
= NULL
;
4960 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4961 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4962 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4963 && MenuItemInfoW
.dwTypeData
!= NULL
)
4965 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
4967 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
4968 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
4984 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4989 SetLastError(ERROR_INVALID_MENU_HANDLE
);
4992 return NtUserSetSystemMenu(hwnd
, hMenu
);
5014 SetLastError( ERROR_INVALID_MENU_HANDLE
);
5018 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
5020 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
5021 if (0 == (Flags
& TPM_NONOTIFY
))
5023 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5026 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
5028 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5030 MenuExitTracking(Wnd
);
5048 /* Not fully implemented */
5049 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5050 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5054 // Example for the Win32/User32 rewrite.
5055 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5069 return NtUserTrackPopupMenuEx( Menu
,
5074 NULL
); // LPTPMPARAMS is null
5083 GetMenuContextHelpId(HMENU hmenu
)
5086 mi
.cbSize
= sizeof(ROSMENUINFO
);
5087 mi
.fMask
= MIM_HELPID
;
5089 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5091 return mi
.dwContextHelpID
;
5112 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5115 Result
= (ULONG_PTR
)lResult
;
5120 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5140 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5143 Result
= (ULONG_PTR
)lResult
;
5148 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5159 LPCWSTR lpszNewItem
,
5164 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5165 for MF_DELETE. We should check the parameters for all others
5166 MF_* actions also (anybody got a doc on ChangeMenu?).
5169 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5172 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5175 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5178 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5181 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5182 flags
&~ MF_REMOVE
);
5184 default : /* MF_INSERT */
5185 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5202 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5203 for MF_DELETE. We should check the parameters for all others
5204 MF_* actions also (anybody got a doc on ChangeMenu?).
5207 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5210 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5213 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5216 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5219 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5220 flags
&~ MF_REMOVE
);
5222 default : /* MF_INSERT */
5223 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);