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 ******************************************************************/
16 #include <wine/debug.h>
17 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
19 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
21 /* internal popup menu window messages */
22 #define MM_SETMENUHANDLE (WM_USER + 0)
23 #define MM_GETMENUHANDLE (WM_USER + 1)
25 /* Internal MenuTrackMenu() flags */
26 #define TPM_INTERNAL 0xF0000000
27 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
28 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
29 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
31 /* TYPES *********************************************************************/
33 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
35 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
36 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
37 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
39 #define IS_SYSTEM_MENU(MenuInfo) \
40 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
42 #define IS_SYSTEM_POPUP(MenuInfo) \
43 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
45 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
47 #define MENU_ITEM_HBMP_SPACE (5)
48 #define MENU_BAR_ITEMS_SPACE (12)
49 #define SEPARATOR_HEIGHT (5)
50 #define MENU_TAB_SPACE (8)
55 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
56 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
57 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
58 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
60 /* internal flags for menu tracking */
62 #define TF_ENDMENU 0x0001
63 #define TF_SUSPENDPOPUP 0x0002
64 #define TF_SKIPREMOVE 0x0004
69 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
70 HMENU TopMenu
; /* initial menu */
71 HWND OwnerWnd
; /* where notifications are sent */
75 static LRESULT WINAPI
PopupMenuWndProcA(HWND hWnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
);
76 static LRESULT WINAPI
PopupMenuWndProcW(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
78 /*********************************************************************
79 * PopupMenu class descriptor
81 const struct builtin_class_descr POPUPMENU_builtin_class
=
83 POPUPMENU_CLASS_ATOMW
, /* name */
84 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
85 (WNDPROC
) NULL
, /* FIXME - procA */
86 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
87 sizeof(MENUINFO
*), /* extra */
88 (LPCWSTR
) IDC_ARROW
, /* cursor */
89 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
93 /* INTERNAL FUNCTIONS ********************************************************/
95 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
96 * Of course I didnt copy the ASM code because we want this to be portable
97 * and it needs to go away.
101 #define GET_WORD(ptr) (*(WORD *)(ptr))
104 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
107 HFONT hMenuFont
= NULL
;
108 HFONT hMenuFontBold
= NULL
;
110 /* Flag set by EndMenu() to force an exit from menu tracking */
111 static BOOL fEndMenu
= FALSE
;
113 /* Use global popup window because there's no way 2 menus can
114 * be tracked at the same time. */
115 static HWND TopPopup
;
117 /* Dimension of the menu bitmaps */
118 static HBITMAP BmpSysMenu
= NULL
;
120 static SIZE MenuCharSize
;
122 /***********************************************************************
125 * Get full information about menu
128 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
130 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
131 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
133 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
136 /***********************************************************************
139 * Set full information about menu
142 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
144 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
145 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
147 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
150 /***********************************************************************
151 * MenuInitRosMenuItemInfo
153 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
156 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
158 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
159 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
162 /***********************************************************************
163 * MenuGetRosMenuItemInfo
165 * Get full information about a menu item
168 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
170 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
172 if (ItemInfo
->dwTypeData
!= NULL
)
174 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
178 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
179 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
180 ItemInfo
->dwTypeData
= NULL
;
182 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
188 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
191 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
192 ItemInfo
->cch
* sizeof(WCHAR
));
193 if (NULL
== ItemInfo
->dwTypeData
)
198 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
203 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
205 ItemInfo
->fMask
= Save_Mask
;
209 /***********************************************************************
210 * MenuSetRosMenuItemInfo
212 * Set selected information about a menu item, need to set the mask bits.
215 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
219 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
220 ItemInfo
->dwTypeData
!= NULL
)
222 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
224 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
229 /***********************************************************************
230 * MenuCleanupRosMenuItemInfo
232 * Cleanup after use of MenuGet/SetRosMenuItemInfo
235 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
237 if (ItemInfo
->dwTypeData
!= NULL
)
239 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
240 ItemInfo
->dwTypeData
= NULL
;
244 /***********************************************************************
245 * MenuGetAllRosMenuItemInfo
247 * Get full information about all menu items
250 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
254 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
255 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
259 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
260 if (NULL
== *ItemInfo
)
265 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
268 /***********************************************************************
269 * MenuCleanupAllRosMenuItemInfo
271 * Cleanup after use of MenuGetAllRosMenuItemInfo
274 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
276 HeapFree(GetProcessHeap(), 0, ItemInfo
);
280 /***********************************************************************
283 * Load the arrow bitmap. We can't do this from MenuInit since user32
284 * can also be used (and thus initialized) from text-mode.
287 MenuLoadBitmaps(VOID
)
289 /* Load system buttons bitmaps */
290 if (NULL
== BmpSysMenu
)
292 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
296 /***********************************************************************
297 * MenuGetBitmapItemSize
299 * Get the size of a bitmap item.
302 MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*Size
, HWND WndOwner
)
305 HBITMAP Bmp
= lpitem
->hbmpItem
;
307 Size
->cx
= Size
->cy
= 0;
309 /* check if there is a magic menu item associated with this item */
310 if (IS_MAGIC_BITMAP(Bmp
))
312 switch((INT_PTR
) Bmp
)
314 case (INT_PTR
)HBMMENU_CALLBACK
:
316 MEASUREITEMSTRUCT measItem
;
317 measItem
.CtlType
= ODT_MENU
;
319 measItem
.itemID
= lpitem
->wID
;
320 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
321 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
322 measItem
.itemData
= lpitem
->dwItemData
;
323 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
324 Size
->cx
= measItem
.itemWidth
;
325 Size
->cy
= measItem
.itemHeight
;
330 case (INT_PTR
) HBMMENU_SYSTEM
:
331 if (0 != lpitem
->dwItemData
)
333 Bmp
= (HBITMAP
) lpitem
->dwItemData
;
337 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
338 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
339 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
340 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
341 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
342 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
343 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
344 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
345 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
346 /* FIXME: Why we need to subtract these magic values? */
347 /* to make them smaller than the menu bar? */
348 Size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
349 Size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
354 if (GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
356 Size
->cx
= Bm
.bmWidth
;
357 Size
->cy
= Bm
.bmHeight
;
361 /***********************************************************************
364 * Draws popup magic glyphs (can be found in system menu).
367 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
370 HFONT hFont
, hOldFont
;
376 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
379 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
382 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
385 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
389 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
392 ZeroMemory(&lf
, sizeof(LOGFONTW
));
393 InflateRect(r
, -2, -2);
394 lf
.lfHeight
= r
->bottom
- r
->top
;
396 lf
.lfWeight
= FW_NORMAL
;
397 lf
.lfCharSet
= DEFAULT_CHARSET
;
398 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
399 hFont
= CreateFontIndirect(&lf
);
400 /* save font and text color */
401 hOldFont
= SelectObject(dc
, hFont
);
402 clrsave
= GetTextColor(dc
);
403 bkmode
= GetBkMode(dc
);
404 /* set color and drawing mode */
405 SetBkMode(dc
, TRANSPARENT
);
411 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
412 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
415 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
416 /* draw selected symbol */
417 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
418 /* restore previous settings */
419 SetTextColor(dc
, clrsave
);
420 SelectObject(dc
, hOldFont
);
421 SetBkMode(dc
, bkmode
);
425 /***********************************************************************
428 * Draw a bitmap item.
431 MenuDrawBitmapItem(HDC Dc
, PROSMENUITEMINFO Item
, const RECT
*Rect
,
432 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
438 int w
= Rect
->right
- Rect
->left
;
439 int h
= Rect
->bottom
- Rect
->top
;
442 HBITMAP hbmpToDraw
= (HBITMAP
) Item
->hbmpItem
;
445 /* Check if there is a magic menu item associated with this item */
446 if (IS_MAGIC_BITMAP(hbmpToDraw
))
452 switch ((INT_PTR
)hbmpToDraw
)
454 case (INT_PTR
) HBMMENU_SYSTEM
:
455 if (NULL
!= Item
->dwTypeData
)
457 Bmp
= (HBITMAP
)Item
->dwTypeData
;
458 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
465 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
467 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
471 /* only use right half of the bitmap */
472 BmpXoffset
= Bm
.bmWidth
/ 2;
473 Bm
.bmWidth
-= BmpXoffset
;
476 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
477 Flags
= DFCS_CAPTIONRESTORE
;
479 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
481 Flags
= DFCS_CAPTIONMIN
;
483 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
485 Flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
487 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
488 Flags
= DFCS_CAPTIONCLOSE
;
490 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
491 Flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
493 case (INT_PTR
) HBMMENU_CALLBACK
:
495 DRAWITEMSTRUCT drawItem
;
497 drawItem
.CtlType
= ODT_MENU
;
499 drawItem
.itemID
= Item
->wID
;
500 drawItem
.itemAction
= odaction
;
501 drawItem
.itemState
= (Item
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
502 drawItem
.itemState
|= (Item
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
503 drawItem
.itemState
|= (Item
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
504 drawItem
.itemState
|= (Item
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
505 drawItem
.itemState
|= (Item
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
506 drawItem
.hwndItem
= (HWND
)hmenu
;
508 drawItem
.rcItem
= *Rect
;
509 drawItem
.itemData
= Item
->dwItemData
;
510 /* some applications make this assumption on the DC's origin */
511 SetViewportOrgEx( Dc
, Item
->Rect
.left
, Item
->Rect
.top
, &origorg
);
512 OffsetRect( &drawItem
.rcItem
, - Item
->Rect
.left
, - Item
->Rect
.top
);
513 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
514 SetViewportOrgEx( Dc
, origorg
.x
, origorg
.y
, NULL
);
519 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
520 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
521 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
522 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
523 MenuDrawPopupGlyph(Dc
, &r
, (INT_PTR
)hbmpToDraw
, Item
->fState
& MF_GRAYED
, Item
->fState
& MF_HILITE
);
526 InflateRect(&r
, -1, -1);
527 if (0 != (Item
->fState
& MF_HILITE
))
529 Flags
|= DFCS_PUSHED
;
531 DrawFrameControl(Dc
, &r
, DFC_CAPTION
, Flags
);
535 if (NULL
== Bmp
|| ! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
541 DcMem
= CreateCompatibleDC(Dc
);
542 SelectObject(DcMem
, Bmp
);
544 /* handle fontsize > bitmap_height */
545 Top
= (Bm
.bmHeight
< h
) ? Rect
->top
+ (h
- Bm
.bmHeight
) / 2 : Rect
->top
;
547 Rop
= ((Item
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmpToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
548 if ((Item
->fState
& MF_HILITE
) && Item
->hbmpItem
)
550 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
552 BitBlt(Dc
, Left
, Top
, w
, h
, DcMem
, BmpXoffset
, 0, Rop
);
556 /***********************************************************************
559 * Draw a single menu item.
562 MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC Dc
,
563 PROSMENUITEMINFO Item
, UINT Height
, BOOL MenuBar
, UINT Action
)
567 BOOL flat_menu
= FALSE
;
569 PWINDOW Wnd
= ValidateHwnd(hWnd
);
574 if (0 != (Item
->fType
& MF_SYSMENU
))
576 if ( (Wnd
->Style
& WS_MINIMIZE
))
578 UserGetInsideRectNC(Wnd
, &Rect
);
579 UserDrawSysMenuButton(hWnd
, Dc
, &Rect
,
580 Item
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
585 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
586 bkgnd
= (MenuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
590 if (0 != (Item
->fState
& MF_HILITE
))
592 if (MenuBar
&& !flat_menu
)
594 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
595 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
599 if (0 != (Item
->fState
& MF_GRAYED
))
601 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
605 SetTextColor(Dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
607 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
612 if (0 != (Item
->fState
& MF_GRAYED
))
614 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
618 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
620 SetBkColor(Dc
, GetSysColor(bkgnd
));
625 if (Item
->fType
& MF_OWNERDRAW
)
628 ** Experimentation under Windows reveals that an owner-drawn
629 ** menu is given the rectangle which includes the space it requested
630 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
631 ** and a popup-menu arrow. This is the value of lpitem->rect.
632 ** Windows will leave all drawing to the application except for
633 ** the popup-menu arrow. Windows always draws that itself, after
634 ** the menu owner has finished drawing.
638 dis
.CtlType
= ODT_MENU
;
640 dis
.itemID
= Item
->wID
;
641 dis
.itemData
= (DWORD
)Item
->dwItemData
;
643 if (0 != (Item
->fState
& MF_CHECKED
))
645 dis
.itemState
|= ODS_CHECKED
;
647 if (0 != (Item
->fState
& MF_GRAYED
))
649 dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
651 if (0 != (Item
->fState
& MF_HILITE
))
653 dis
.itemState
|= ODS_SELECTED
;
655 dis
.itemAction
= Action
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
656 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
659 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
660 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
661 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
662 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
664 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
665 /* Draw the popup-menu arrow */
666 if (0 != (Item
->fType
& MF_POPUP
))
669 CopyRect(&rectTemp
, &Rect
);
670 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
671 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
676 TRACE("rect={%ld,%ld,%ld,%ld}\n", Item
->Rect
.left
, Item
->Rect
.top
,
677 Item
->Rect
.right
, Item
->Rect
.bottom
);
679 if (MenuBar
&& 0 != (Item
->fType
& MF_SEPARATOR
))
684 if (Item
->fState
& MF_HILITE
)
688 InflateRect (&Rect
, -1, -1);
689 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
690 InflateRect (&Rect
, 1, 1);
691 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
697 DrawEdge(Dc
, &Rect
, BDR_SUNKENOUTER
, BF_RECT
);
701 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
707 FillRect(Dc
, &Rect
, GetSysColorBrush(bkgnd
));
710 SetBkMode(Dc
, TRANSPARENT
);
712 /* vertical separator */
713 if (! MenuBar
&& 0 != (Item
->fType
& MF_MENUBARBREAK
))
719 rc
.bottom
= Height
- 3;
722 oldPen
= SelectObject( Dc
, GetStockObject(DC_PEN
) );
723 SetDCPenColor(Dc
, GetSysColor(COLOR_BTNSHADOW
));
724 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
725 LineTo( Dc
, rc
.left
, rc
.bottom
);
726 SelectObject( Dc
, oldPen
);
729 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
732 /* horizontal separator */
733 if (0 != (Item
->fType
& MF_SEPARATOR
))
739 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
742 oldPen
= SelectObject( Dc
, GetStockObject(DC_PEN
) );
743 SetDCPenColor(Dc
, GetSysColor(COLOR_BTNSHADOW
));
744 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
745 LineTo( Dc
, rc
.right
, rc
.top
);
746 SelectObject( Dc
, oldPen
);
749 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_TOP
);
754 /* helper lines for debugging */
755 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
756 FrameRect(Dc
, &Rect
, GetStockObject(BLACK_BRUSH
));
757 SelectObject(Dc
, GetStockObject(DC_PEN
));
758 SetDCPenColor(Dc
, GetSysColor(COLOR_WINDOWFRAME
));
759 MoveToEx(Dc
, Rect
.left
, (Rect
.top
+ Rect
.bottom
) / 2, NULL
);
760 LineTo(Dc
, Rect
.right
, (Rect
.top
+ Rect
.bottom
) / 2);
765 INT y
= Rect
.top
+ Rect
.bottom
;
767 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
768 UINT CheckBitmapHeight
= GetSystemMetrics(SM_CYMENUCHECK
);
770 /* Draw the check mark
773 * Custom checkmark bitmaps are monochrome but not always 1bpp.
775 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
777 HBITMAP bm
= 0 != (Item
->fState
& MF_CHECKED
) ? Item
->hbmpChecked
: Item
->hbmpUnchecked
;
778 if (NULL
!= bm
) /* we have a custom bitmap */
780 HDC DcMem
= CreateCompatibleDC(Dc
);
781 SelectObject(DcMem
, bm
);
782 BitBlt(Dc
, Rc
.left
, (y
- CheckBitmapHeight
) / 2,
783 CheckBitmapWidth
, CheckBitmapHeight
,
784 DcMem
, 0, 0, SRCCOPY
);
788 else if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
791 CopyRect(&rectTemp
, &Rect
);
792 rectTemp
.right
= rectTemp
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
793 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
,
794 0 != (Item
->fType
& MFT_RADIOCHECK
) ?
795 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
802 CopyRect(&bmpRect
, &Rect
);
803 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
804 bmpRect
.left
+= CheckBitmapWidth
+ 2;
805 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
807 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
808 MenuDrawBitmapItem(Dc
, Item
, &bmpRect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
811 /* Draw the popup-menu arrow */
812 if (0 != (Item
->fType
& MF_POPUP
))
815 CopyRect(&rectTemp
, &Rect
);
816 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
817 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
820 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
821 Rect
.left
+= CheckBitmapWidth
;
822 Rect
.right
-= CheckBitmapWidth
;
824 else if (Item
->hbmpItem
) /* Draw the bitmap */
826 MenuDrawBitmapItem(Dc
, Item
, &Rect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
829 /* No bitmap - process text if present */
833 HFONT FontOld
= NULL
;
835 UINT uFormat
= MenuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
836 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
838 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
839 Rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
841 Rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
843 if (0 != (Item
->fState
& MFS_DEFAULT
))
845 FontOld
= SelectObject(Dc
, hMenuFontBold
);
850 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
851 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
854 Text
= (PWCHAR
) Item
->dwTypeData
;
857 for (i
= 0; L
'\0' != Text
[i
]; i
++)
859 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
866 if (0 != (Item
->fState
& MF_GRAYED
))
868 if (0 == (Item
->fState
& MF_HILITE
))
870 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
871 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
872 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
873 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
875 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
878 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
880 /* paint the shortcut text */
881 if (! MenuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
883 if (L
'\t' == Text
[i
])
885 Rect
.left
= Item
->XTab
;
886 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
890 Rect
.right
= Item
->XTab
;
891 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
894 if (0 != (Item
->fState
& MF_GRAYED
))
896 if (0 == (Item
->fState
& MF_HILITE
))
898 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
899 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
900 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
901 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
903 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
905 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
910 SelectObject(Dc
, FontOld
);
915 /***********************************************************************
918 * Paint a popup menu.
921 MenuDrawPopupMenu(HWND Wnd
, HDC Dc
, HMENU Menu
)
923 HBRUSH PrevBrush
= NULL
;
926 ROSMENUINFO MenuInfo
;
927 ROSMENUITEMINFO ItemInfo
;
930 TRACE("wnd=%x dc=%x menu=%x\n", Wnd
, Dc
, Menu
);
932 GetClientRect(Wnd
, &Rect
);
934 if (NULL
!= (PrevBrush
= SelectObject(Dc
, GetSysColorBrush(COLOR_MENU
)))
935 && NULL
!= SelectObject(Dc
, hMenuFont
))
937 Rectangle(Dc
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
939 PrevPen
= SelectObject(Dc
, GetStockObject(NULL_PEN
));
942 BOOL flat_menu
= FALSE
;
944 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
946 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
948 DrawEdge(Dc
, &Rect
, EDGE_RAISED
, BF_RECT
);
950 /* draw menu items */
952 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 != MenuInfo
.MenuItemCount
)
954 MenuInitRosMenuItemInfo(&ItemInfo
);
956 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
958 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
960 MenuDrawMenuItem(Wnd
, &MenuInfo
, MenuInfo
.WndOwner
, Dc
, &ItemInfo
,
961 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
965 MenuCleanupRosMenuItemInfo(&ItemInfo
);
970 SelectObject(Dc
, PrevBrush
);
975 static LRESULT WINAPI
976 PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
978 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
984 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
985 SetWindowLongPtrA(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
989 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
990 return MA_NOACTIVATE
;
995 BeginPaint(Wnd
, &ps
);
996 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1005 /* zero out global pointer in case resident popup window was destroyed. */
1006 if (Wnd
== TopPopup
)
1015 if (0 == GetWindowLongPtrA(Wnd
, 0))
1017 OutputDebugStringA("no menu to display\n");
1022 SetWindowLongPtrA(Wnd
, 0, 0);
1026 case MM_SETMENUHANDLE
:
1027 SetWindowLongPtrA(Wnd
, 0, wParam
);
1030 case MM_GETMENUHANDLE
:
1031 return GetWindowLongPtrA(Wnd
, 0);
1034 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1039 static LRESULT WINAPI
1040 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1042 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1048 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1049 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1053 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1054 return MA_NOACTIVATE
;
1059 BeginPaint(Wnd
, &ps
);
1060 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1069 /* zero out global pointer in case resident popup window was destroyed. */
1070 if (Wnd
== TopPopup
)
1079 if (0 == GetWindowLongPtrW(Wnd
, 0))
1081 OutputDebugStringA("no menu to display\n");
1086 SetWindowLongPtrW(Wnd
, 0, 0);
1090 case MM_SETMENUHANDLE
:
1091 SetWindowLongPtrW(Wnd
, 0, wParam
);
1094 case MM_GETMENUHANDLE
:
1095 return GetWindowLongPtrW(Wnd
, 0);
1098 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1104 /**********************************************************************
1105 * MENUEX_ParseResource
1107 * Parse an extended menu resource and add items to the menu.
1108 * Return a pointer to the end of the resource.
1110 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
1112 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1120 mii
.cbSize
= sizeof(mii
);
1121 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
1122 mii
.fType
= GET_DWORD(res
);
1123 res
+= sizeof(DWORD
);
1124 mii
.fState
= GET_DWORD(res
);
1125 res
+= sizeof(DWORD
);
1126 mii
.wID
= GET_DWORD(res
);
1127 res
+= sizeof(DWORD
);
1128 resinfo
= GET_WORD(res
);
1129 res
+= sizeof(WORD
);
1130 /* Align the text on a word boundary. */
1131 res
+= (~((int)res
- 1)) & 1;
1132 mii
.dwTypeData
= (LPWSTR
) res
;
1133 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1134 /* Align the following fields on a dword boundary. */
1135 res
+= (~((int)res
- 1)) & 3;
1137 if (resinfo
& 1) /* Pop-up? */
1139 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1140 res
+= sizeof(DWORD
);
1141 mii
.hSubMenu
= CreatePopupMenu();
1144 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1146 DestroyMenu(mii
.hSubMenu
);
1149 mii
.fMask
|= MIIM_SUBMENU
;
1150 mii
.fType
|= MF_POPUP
;
1151 mii
.wID
= (UINT
) mii
.hSubMenu
;
1153 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1155 mii
.fType
|= MF_SEPARATOR
;
1157 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1159 while (!(resinfo
& MF_END
));
1164 /**********************************************************************
1165 * MENU_ParseResource
1167 * Parse a standard menu resource and add items to the menu.
1168 * Return a pointer to the end of the resource.
1170 * NOTE: flags is equivalent to the mtOption field
1172 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1181 flags
= GET_WORD(res
);
1183 /* remove MF_END flag before passing it to AppendMenu()! */
1184 end
= (flags
& MF_END
);
1185 if(end
) flags
^= MF_END
;
1187 res
+= sizeof(WORD
);
1188 if(!(flags
& MF_POPUP
))
1191 res
+= sizeof(WORD
);
1195 res
+= strlen(str
) + 1;
1197 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1198 if (flags
& MF_POPUP
)
1200 hSubMenu
= CreatePopupMenu();
1201 if(!hSubMenu
) return NULL
;
1202 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1205 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1207 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1209 else /* Not a popup */
1212 flags
= MF_SEPARATOR
;
1214 if (flags
& MF_SEPARATOR
)
1216 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1217 flags
|= MF_GRAYED
| MF_DISABLED
;
1221 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1223 AppendMenuW(hMenu
, flags
, id
,
1224 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1233 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1235 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
1236 LRESULT Result
= (LRESULT
)hmenu
;
1238 // removing space for checkboxes from menu
1239 MENUINFO menuinfo
= {0};
1240 menuinfo
.cbSize
= sizeof(menuinfo
);
1241 menuinfo
.fMask
= MIM_STYLE
;
1242 GetMenuInfo(hmenu
, &menuinfo
);
1243 menuinfo
.dwStyle
|= MNS_NOCHECK
;
1244 SetMenuInfo(hmenu
, &menuinfo
);
1246 // adding bitmaps to menu items
1247 MENUITEMINFOW info
= {0};
1248 info
.cbSize
= sizeof(info
);
1249 info
.fMask
|= MIIM_BITMAP
;
1250 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
1251 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
1252 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
1253 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
1254 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
1255 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
1256 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
1257 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
1259 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1266 NONCLIENTMETRICSW ncm
;
1268 /* get the menu font */
1269 if(!hMenuFont
|| !hMenuFontBold
)
1271 ncm
.cbSize
= sizeof(ncm
);
1272 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1274 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1278 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1279 if(hMenuFont
== NULL
)
1281 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1285 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1286 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1287 if(hMenuFontBold
== NULL
)
1289 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1290 DeleteObject(hMenuFont
);
1305 DeleteObject(hMenuFont
);
1311 DeleteObject(hMenuFontBold
);
1312 hMenuFontBold
= NULL
;
1318 /***********************************************************************
1321 * Calculate the size of the menu item and store it in ItemInfo->rect.
1323 static void FASTCALL
1324 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, PROSMENUINFO MenuInfo
, HWND WndOwner
,
1325 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1329 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1331 TRACE("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1333 MenuCharSize
.cx
= GdiGetCharDimensions( Dc
, NULL
, &MenuCharSize
.cy
);
1335 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1337 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1340 ** Experimentation under Windows reveals that an owner-drawn
1341 ** menu is expected to return the size of the content part of
1342 ** the menu item, not including the checkmark nor the submenu
1343 ** arrow. Windows adds those values itself and returns the
1344 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1346 MEASUREITEMSTRUCT mis
;
1347 mis
.CtlType
= ODT_MENU
;
1349 mis
.itemID
= ItemInfo
->wID
;
1350 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1351 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1353 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1354 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1355 * width of a menufont character to the width of an owner-drawn menu.
1357 ItemInfo
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1361 /* under at least win95 you seem to be given a standard
1362 height for the menu and the height value is ignored */
1363 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1367 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1370 TRACE("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1374 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1376 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1378 ItemInfo
->Rect
.right
+= CheckBitmapWidth
+ MenuCharSize
.cx
;
1384 if (ItemInfo
->hbmpItem
)
1388 if (!MenuBar
) /* hbmpItem */
1390 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1391 /* Keep the size of the bitmap in callback mode to be able
1392 * to draw it correctly */
1393 ItemInfo
->Rect
.right
= ItemInfo
->Rect
.left
+ Size
.cx
;
1394 if (MenuInfo
->maxBmpSize
.cx
< abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
||
1395 MenuInfo
->maxBmpSize
.cy
< abs(Size
.cy
))
1397 MenuInfo
->maxBmpSize
.cx
= abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
;
1398 MenuInfo
->maxBmpSize
.cy
= abs(Size
.cy
);
1400 MenuSetRosMenuInfo(MenuInfo
);
1401 itemheight
= Size
.cy
+ 2;
1403 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1404 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1405 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1406 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1407 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1409 else /* hbmpItem & MenuBar */
1411 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1412 ItemInfo
->Rect
.right
+= Size
.cx
;
1413 if( ItemInfo
->Text
) ItemInfo
->Rect
.right
+= 2;
1414 itemheight
= Size
.cy
;
1416 /* Special case: Minimize button doesn't have a space behind it. */
1417 if (ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1418 ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1419 ItemInfo
->Rect
.right
-= 1;
1424 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1425 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1426 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1427 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1428 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1431 /* it must be a text item - unless it's the system menu */
1432 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && ItemInfo
->Text
)
1434 HFONT hfontOld
= NULL
;
1435 RECT rc
= ItemInfo
->Rect
;
1436 LONG txtheight
, txtwidth
;
1438 if ( ItemInfo
->fState
& MFS_DEFAULT
)
1440 hfontOld
= SelectObject( Dc
, hMenuFontBold
);
1444 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1445 DT_SINGLELINE
|DT_CALCRECT
);
1446 ItemInfo
->Rect
.right
+= rc
.right
- rc
.left
;
1447 itemheight
= max( max( itemheight
, txtheight
),
1448 GetSystemMetrics( SM_CYMENU
) - 1);
1449 ItemInfo
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1453 if ((p
= strchrW( ItemInfo
->dwTypeData
, '\t' )) != NULL
)
1457 int n
= (int)( p
- ItemInfo
->dwTypeData
);
1458 /* Item contains a tab (only meaningful in popup menus) */
1459 /* get text size before the tab */
1460 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, n
, &rc
,
1461 DT_SINGLELINE
|DT_CALCRECT
);
1462 txtwidth
= rc
.right
- rc
.left
;
1463 p
+= 1; /* advance past the Tab */
1464 /* get text size after the tab */
1465 tmpheight
= DrawTextW( Dc
, p
, -1, &tmprc
, DT_SINGLELINE
|DT_CALCRECT
);
1466 ItemInfo
->XTab
+= txtwidth
;
1467 txtheight
= max( txtheight
, tmpheight
);
1468 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1469 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1473 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1474 DT_SINGLELINE
|DT_CALCRECT
);
1475 txtwidth
= rc
.right
- rc
.left
;
1476 ItemInfo
->XTab
+= txtwidth
;
1478 ItemInfo
->Rect
.right
+= 2 + txtwidth
;
1479 itemheight
= max( itemheight
, max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1481 if (hfontOld
) SelectObject (Dc
, hfontOld
);
1485 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1487 ItemInfo
->Rect
.bottom
+= itemheight
;
1488 TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1491 /***********************************************************************
1492 * MenuPopupMenuCalcSize
1494 * Calculate the size of a popup menu.
1496 static void FASTCALL
1497 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1499 ROSMENUITEMINFO ItemInfo
;
1502 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1504 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1505 if (0 == MenuInfo
->MenuItemCount
)
1507 MenuSetRosMenuInfo(MenuInfo
);
1512 SelectObject(Dc
, hMenuFont
);
1517 MenuInfo
->maxBmpSize
.cx
= 0;
1518 MenuInfo
->maxBmpSize
.cy
= 0;
1520 MenuInitRosMenuItemInfo(&ItemInfo
);
1521 while (Start
< MenuInfo
->MenuItemCount
)
1526 MaxTab
= MaxTabWidth
= 0;
1528 /* Parse items until column break or end of menu */
1529 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1531 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1533 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1534 MenuSetRosMenuInfo(MenuInfo
);
1538 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1542 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1543 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1545 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1546 MenuSetRosMenuInfo(MenuInfo
);
1549 // Not sure here,, The patch from wine removes this.
1550 // if (0 != (ItemInfo.fType & MF_MENUBARBREAK))
1554 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1555 OrgY
= ItemInfo
.Rect
.bottom
;
1556 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1558 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1559 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1563 /* Finish the column (set all items to the largest width found) */
1564 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1567 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1569 ItemInfo
.Rect
.right
= MaxX
;
1570 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1572 ItemInfo
.XTab
= MaxTab
;
1574 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1578 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1581 MenuInfo
->Width
= MaxX
;
1583 /* space for 3d border */
1584 MenuInfo
->Height
+= 2;
1585 MenuInfo
->Width
+= 2;
1587 ReleaseDC(NULL
, Dc
);
1588 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1589 MenuSetRosMenuInfo(MenuInfo
);
1592 /***********************************************************************
1593 * MenuMenuBarCalcSize
1595 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1596 * height is off by 1 pixel which causes lengthy window relocations when
1597 * active document window is maximized/restored.
1599 * Calculate the size of the menu bar.
1601 static void FASTCALL
1602 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1604 ROSMENUITEMINFO ItemInfo
;
1605 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1607 if (NULL
== Rect
|| NULL
== MenuInfo
)
1611 if (0 == MenuInfo
->MenuItemCount
)
1616 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1617 Rect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1618 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1619 MenuInfo
->Height
= 0;
1620 MaxY
= Rect
->top
+ 1;
1624 MenuInfo
->maxBmpSize
.cx
= 0;
1625 MenuInfo
->maxBmpSize
.cy
= 0;
1627 MenuInitRosMenuItemInfo(&ItemInfo
);
1628 while (Start
< MenuInfo
->MenuItemCount
)
1630 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1632 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1638 /* Parse items until line break or end of menu */
1639 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1641 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1646 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1651 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1652 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1653 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1655 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1659 if (ItemInfo
.Rect
.right
> Rect
->right
)
1667 ItemInfo
.Rect
.right
= Rect
->right
;
1670 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1671 OrgX
= ItemInfo
.Rect
.right
;
1672 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1674 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1676 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1682 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1683 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1685 /* Finish the line (set all items to the largest height found) */
1688 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1690 ItemInfo
.Rect
.bottom
= MaxY
;
1691 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1696 Start
= i
; /* This works! */
1700 Rect
->bottom
= MaxY
;
1701 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1702 MenuSetRosMenuInfo(MenuInfo
);
1706 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1707 /* the last item (if several lines, only move the last line) */
1708 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1710 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1713 OrgY
= ItemInfo
.Rect
.top
;
1715 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1721 if (ItemInfo
.Rect
.top
!= OrgY
)
1723 break; /* Other line */
1725 if (OrgX
<= ItemInfo
.Rect
.right
)
1727 break; /* Too far right already */
1729 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1730 ItemInfo
.Rect
.right
= OrgX
;
1731 OrgX
= ItemInfo
.Rect
.left
;
1732 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1733 if (HelpPos
+ 1 <= i
&&
1734 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1736 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1742 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1745 /***********************************************************************
1746 * DrawMenuBarTemp (USER32.@)
1750 * called by W98SE desk.cpl Control Panel Applet
1752 * Not 100% sure about the param names, but close.
1757 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1759 ROSMENUINFO MenuInfo
;
1760 ROSMENUITEMINFO ItemInfo
;
1762 HFONT FontOld
= NULL
;
1763 BOOL flat_menu
= FALSE
;
1765 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1769 Menu
= GetMenu(Wnd
);
1777 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1779 return GetSystemMetrics(SM_CYMENU
);
1782 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1784 FontOld
= SelectObject(DC
, Font
);
1786 if (0 == MenuInfo
.Height
)
1788 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1791 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1793 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
1795 SelectObject(DC
, GetStockObject(DC_PEN
));
1796 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
1797 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1798 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1800 if (0 == MenuInfo
.MenuItemCount
)
1802 SelectObject(DC
, FontOld
);
1803 return GetSystemMetrics(SM_CYMENU
);
1806 MenuInitRosMenuItemInfo(&ItemInfo
);
1807 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1809 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1811 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1812 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1815 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1817 SelectObject(DC
, FontOld
);
1819 return MenuInfo
.Height
;
1823 /***********************************************************************
1826 * Paint a menu bar. Returns the height of the menu bar.
1827 * called from [windows/nonclient.c]
1829 UINT
MenuDrawMenuBar(HDC DC
, LPRECT Rect
, HWND Wnd
, BOOL SuppressDraw
)
1831 ROSMENUINFO MenuInfo
;
1832 HFONT FontOld
= NULL
;
1833 HMENU Menu
= GetMenu(Wnd
);
1835 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1837 return GetSystemMetrics(SM_CYMENU
);
1842 FontOld
= SelectObject(DC
, hMenuFont
);
1844 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1846 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1848 if (NULL
!= FontOld
)
1850 SelectObject(DC
, FontOld
);
1852 return MenuInfo
.Height
;
1856 return DrawMenuBarTemp(Wnd
, DC
, Rect
, Menu
, NULL
);
1860 /***********************************************************************
1863 static BOOL FASTCALL
1864 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1866 TRACE("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1870 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1871 if (0 == (Flags
& TPM_NONOTIFY
))
1873 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1876 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1878 if (0 == (Flags
& TPM_NONOTIFY
))
1880 ROSMENUINFO MenuInfo
;
1882 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1884 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
1886 if (0 == MenuInfo
.Height
)
1888 /* app changed/recreated menu bar entries in WM_INITMENU
1889 Recalculate menu sizes else clicks will not work */
1890 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1891 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1894 /* This makes the menus of applications built with Delphi work.
1895 * It also enables menus to be displayed in more than one window,
1896 * but there are some bugs left that need to be fixed in this case.
1898 if(MenuInfo
.Self
== Menu
)
1901 MenuSetRosMenuInfo(&MenuInfo
);
1909 /***********************************************************************
1912 * Display a popup menu.
1914 static BOOL FASTCALL
1915 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1916 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1918 ROSMENUINFO MenuInfo
;
1919 ROSMENUITEMINFO ItemInfo
;
1922 TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1923 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1925 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1930 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1932 MenuInitRosMenuItemInfo(&ItemInfo
);
1933 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1935 ItemInfo
.fMask
|= MIIM_STATE
;
1936 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1937 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1939 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1940 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1943 /* store the owner for DrawItem */
1944 MenuInfo
.WndOwner
= WndOwner
;
1945 MenuSetRosMenuInfo(&MenuInfo
);
1947 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1949 /* adjust popup menu pos so that it fits within the desktop */
1951 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1952 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1954 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1956 if (0 != XAnchor
&& X
>= Width
- XAnchor
)
1958 X
-= Width
- XAnchor
;
1960 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1962 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1970 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1972 if (0 != YAnchor
&& Y
>= Height
+ YAnchor
)
1974 Y
-= Height
+ YAnchor
;
1976 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1978 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
1987 /* NOTE: In Windows, top menu popup is not owned. */
1988 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
1989 WS_POPUP
, X
, Y
, Width
, Height
,
1990 WndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(WndOwner
, GWLP_HINSTANCE
),
1991 (LPVOID
) MenuInfo
.Self
);
1992 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
1996 if (NULL
== TopPopup
)
1998 TopPopup
= MenuInfo
.Wnd
;
2001 /* Display the window */
2002 SetWindowPos(MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
2003 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2004 UpdateWindow(MenuInfo
.Wnd
);
2009 /***********************************************************************
2012 * Find a Sub menu. Return the position of the submenu, and modifies
2013 * *hmenu in case it is found in another sub-menu.
2014 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
2016 static UINT FASTCALL
2017 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
2019 ROSMENUINFO MenuInfo
;
2020 ROSMENUITEMINFO ItemInfo
;
2025 if ((HMENU
) 0xffff == *Menu
2026 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
2028 return NO_SELECTED_ITEM
;
2031 MenuInitRosMenuItemInfo(&ItemInfo
);
2032 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2034 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2036 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2037 return NO_SELECTED_ITEM
;
2039 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2043 if (ItemInfo
.hSubMenu
== SubTarget
)
2045 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2048 SubMenu
= ItemInfo
.hSubMenu
;
2049 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
2050 if (NO_SELECTED_ITEM
!= Pos
)
2056 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2058 return NO_SELECTED_ITEM
;
2061 /***********************************************************************
2064 static void FASTCALL
2065 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
2066 BOOL SendMenuSelect
, HMENU TopMenu
)
2069 ROSMENUITEMINFO ItemInfo
;
2070 ROSMENUINFO TopMenuInfo
;
2073 TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
2075 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
2080 if (MenuInfo
->FocusedItem
== Index
)
2085 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2087 Dc
= GetDC(MenuInfo
->Wnd
);
2091 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2094 if (NULL
== TopPopup
)
2096 TopPopup
= MenuInfo
->Wnd
;
2099 SelectObject(Dc
, hMenuFont
);
2100 MenuInitRosMenuItemInfo(&ItemInfo
);
2101 /* Clear previous highlighted item */
2102 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2104 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2106 ItemInfo
.fMask
|= MIIM_STATE
;
2107 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2108 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2110 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
2111 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2115 /* Highlight new item (if any) */
2116 MenuInfo
->FocusedItem
= Index
;
2117 MenuSetRosMenuInfo(MenuInfo
);
2118 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2120 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2122 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2124 ItemInfo
.fMask
|= MIIM_STATE
;
2125 ItemInfo
.fState
|= MF_HILITE
;
2126 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2127 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
2128 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2133 SendMessageW(WndOwner
, WM_MENUSELECT
,
2134 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
2135 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
2136 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
2140 else if (SendMenuSelect
)
2142 if (NULL
!= TopMenu
)
2144 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
2145 if (NO_SELECTED_ITEM
!= Pos
)
2147 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
2148 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
2150 SendMessageW(WndOwner
, WM_MENUSELECT
,
2151 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
2153 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
2159 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2160 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2163 /***********************************************************************
2166 * Moves currently selected item according to the Offset parameter.
2167 * If there is no selection then it should select the last item if
2168 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2170 static void FASTCALL
2171 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2174 ROSMENUITEMINFO ItemInfo
;
2177 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2179 /* Prevent looping */
2180 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
2182 else if (Offset
< -1)
2184 else if (Offset
> 1)
2187 MenuInitRosMenuItemInfo(&ItemInfo
);
2189 OrigPos
= MenuInfo
->FocusedItem
;
2190 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2197 i
= MenuInfo
->FocusedItem
;
2204 /* Clip and wrap around */
2207 i
= MenuInfo
->MenuItemCount
- 1;
2209 else if (i
>= MenuInfo
->MenuItemCount
)
2213 /* If this is a good candidate; */
2214 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2215 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2217 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2218 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2221 } while (i
!= OrigPos
);
2224 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2227 /***********************************************************************
2228 * MenuInitSysMenuPopup
2230 * Grey the appropriate items in System menu.
2233 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2241 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2242 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2243 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2244 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2245 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2246 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2247 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2248 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2249 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2250 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2251 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2253 /* The menu item must keep its state if it's disabled */
2256 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2259 /* Set default menu item */
2260 if(Style
& WS_MINIMIZE
)
2262 DefItem
= SC_RESTORE
;
2266 if(HitTest
== HTCAPTION
)
2268 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2276 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2277 mii
.fMask
|= MIIM_STATE
;
2278 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2279 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2284 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2287 /***********************************************************************
2290 * Display the sub-menu of the selected item of this menu.
2291 * Return the handle of the submenu, or menu if no submenu to display.
2293 static HMENU FASTCALL
2294 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2296 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2298 ROSMENUITEMINFO ItemInfo
;
2299 ROSMENUINFO SubMenuInfo
;
2303 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2305 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2307 return MenuInfo
->Self
;
2310 MenuInitRosMenuItemInfo(&ItemInfo
);
2311 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2313 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2314 return MenuInfo
->Self
;
2316 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2318 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2319 return MenuInfo
->Self
;
2322 /* message must be sent before using item,
2323 because nearly everything may be changed by the application ! */
2325 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2326 if (0 == (Flags
& TPM_NONOTIFY
))
2328 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2329 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2332 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2334 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2335 return MenuInfo
->Self
;
2337 Rect
= ItemInfo
.Rect
;
2339 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2340 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2342 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2344 Dc
= GetDC(MenuInfo
->Wnd
);
2348 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2351 SelectObject(Dc
, hMenuFont
);
2352 ItemInfo
.fMask
|= MIIM_STATE
;
2353 ItemInfo
.fState
|= MF_HILITE
;
2354 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2355 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2356 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2357 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2360 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2361 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2363 ItemInfo
.Rect
= Rect
;
2366 ItemInfo
.fMask
|= MIIM_STATE
;
2367 ItemInfo
.fState
|= MF_MOUSESELECT
;
2368 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2370 if (IS_SYSTEM_MENU(MenuInfo
))
2372 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2373 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2375 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2376 Rect
.top
= Rect
.bottom
;
2377 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2378 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2382 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2383 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2385 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2386 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2387 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2388 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2389 - GetSystemMetrics(SM_CYBORDER
);
2393 Rect
.left
+= ItemInfo
.Rect
.left
;
2394 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2395 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2396 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2400 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2401 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2402 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2404 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2407 Ret
= ItemInfo
.hSubMenu
;
2408 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2413 /***********************************************************************
2416 * Hide the sub-popup menus of this menu.
2418 static void FASTCALL
2419 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2421 ROSMENUINFO SubMenuInfo
;
2422 ROSMENUITEMINFO ItemInfo
;
2424 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2426 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2428 MenuInitRosMenuItemInfo(&ItemInfo
);
2429 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2430 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2431 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2432 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2434 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2437 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2438 ItemInfo
.fMask
|= MIIM_STATE
;
2439 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2440 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2442 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2443 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2444 DestroyWindow(SubMenuInfo
.Wnd
);
2445 SubMenuInfo
.Wnd
= NULL
;
2446 MenuSetRosMenuInfo(&SubMenuInfo
);
2451 /***********************************************************************
2452 * MenuSwitchTracking
2454 * Helper function for menu navigation routines.
2456 static void FASTCALL
2457 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2459 ROSMENUINFO TopMenuInfo
;
2461 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2463 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2464 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2465 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2467 /* both are top level menus (system and menu-bar) */
2468 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2469 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2470 Mt
->TopMenu
= PtMenuInfo
->Self
;
2474 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2477 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2480 /***********************************************************************
2481 * MenuExecFocusedItem
2483 * Execute a menu item (for instance when user pressed Enter).
2484 * Return the wID of the executed item. Otherwise, -1 indicating
2485 * that no menu item was executed, -2 if a popup is shown;
2486 * Have to receive the flags for the TrackPopupMenu options to avoid
2487 * sending unwanted message.
2491 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2493 ROSMENUITEMINFO ItemInfo
;
2496 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2498 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2503 MenuInitRosMenuItemInfo(&ItemInfo
);
2504 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2506 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2510 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2512 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2514 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2515 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2517 /* If TPM_RETURNCMD is set you return the id, but
2518 do not send a message to the owner */
2519 if (0 == (Flags
& TPM_RETURNCMD
))
2521 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2523 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2524 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2528 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2529 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2530 MenuInfo
->FocusedItem
,
2531 (LPARAM
)MenuInfo
->Self
);
2533 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2537 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2543 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2550 /***********************************************************************
2553 * Return TRUE if we can go on with menu tracking.
2555 static BOOL FASTCALL
2556 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2559 ROSMENUINFO MenuInfo
;
2560 ROSMENUITEMINFO Item
;
2562 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2566 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2570 if (IS_SYSTEM_MENU(&MenuInfo
))
2576 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2578 MenuInitRosMenuItemInfo(&Item
);
2579 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2581 MenuCleanupRosMenuItemInfo(&Item
);
2585 if (!(Item
.fType
& MF_SEPARATOR
) &&
2586 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2588 if (MenuInfo
.FocusedItem
!= Index
)
2590 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2593 /* If the popup menu is not already "popped" */
2594 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2596 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2600 MenuCleanupRosMenuItemInfo(&Item
);
2605 /* else the click was on the menu bar, finish the tracking */
2610 /***********************************************************************
2613 * Return the value of MenuExecFocusedItem if
2614 * the selected item was not a popup. Else open the popup.
2615 * A -1 return value indicates that we go on with menu tracking.
2619 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2622 ROSMENUINFO MenuInfo
;
2623 ROSMENUITEMINFO ItemInfo
;
2625 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2630 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2635 if (! IS_SYSTEM_MENU(&MenuInfo
))
2637 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2639 MenuInitRosMenuItemInfo(&ItemInfo
);
2640 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2641 MenuInfo
.FocusedItem
== Id
)
2643 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2645 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2646 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2647 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2649 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2651 /* If we are dealing with the top-level menu */
2652 /* and this is a click on an already "popped" item: */
2653 /* Stop the menu tracking and close the opened submenus */
2654 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2656 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2660 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2661 MenuInfo
.TimeToHide
= TRUE
;
2662 MenuSetRosMenuInfo(&MenuInfo
);
2668 /***********************************************************************
2671 * Walks menu chain trying to find a menu pt maps to.
2673 static HMENU FASTCALL
2674 MenuPtMenu(HMENU Menu
, POINT Pt
)
2676 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2677 ROSMENUINFO MenuInfo
;
2678 ROSMENUITEMINFO ItemInfo
;
2682 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2687 /* try subpopup first (if any) */
2688 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2690 MenuInitRosMenuItemInfo(&ItemInfo
);
2691 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2692 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2693 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2695 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2698 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2702 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2705 /* check the current window (avoiding WM_HITTEST) */
2706 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2707 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2709 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2714 else if (HTSYSMENU
== Ht
)
2716 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2718 else if (HTMENU
== Ht
)
2720 Ret
= GetMenu(MenuInfo
.Wnd
);
2726 /***********************************************************************
2729 * Return TRUE if we can go on with menu tracking.
2731 static BOOL FASTCALL
2732 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2735 ROSMENUINFO MenuInfo
;
2736 ROSMENUITEMINFO ItemInfo
;
2740 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2744 if (IS_SYSTEM_MENU(&MenuInfo
))
2750 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2755 Index
= NO_SELECTED_ITEM
;
2758 if (NO_SELECTED_ITEM
== Index
)
2760 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2761 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2763 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2767 else if (MenuInfo
.FocusedItem
!= Index
)
2769 MenuInitRosMenuItemInfo(&ItemInfo
);
2770 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2771 !(ItemInfo
.fType
& MF_SEPARATOR
))
2773 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2774 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2775 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2777 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2783 /******************************************************************************
2785 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2787 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2790 PROSMENUITEMINFO MenuItems
;
2792 i
= MenuInfo
->FocusedItem
;
2793 if (NO_SELECTED_ITEM
== i
)
2798 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2800 return NO_SELECTED_ITEM
;
2803 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2805 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2811 return NO_SELECTED_ITEM
;
2814 /******************************************************************************
2816 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2818 static UINT FASTCALL
2819 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2822 PROSMENUITEMINFO MenuItems
;
2824 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2826 return NO_SELECTED_ITEM
;
2829 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2831 return NO_SELECTED_ITEM
;
2834 /* Find the start of the column */
2836 for (i
= MenuInfo
->FocusedItem
;
2837 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2845 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2846 return NO_SELECTED_ITEM
;
2849 for (--i
; 0 != i
; --i
)
2851 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2857 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2858 TRACE("ret %d.\n", i
);
2863 /***********************************************************************
2866 * Return the handle of the selected sub-popup menu (if any).
2868 static HMENU FASTCALL
2869 MenuGetSubPopup(HMENU Menu
)
2871 ROSMENUINFO MenuInfo
;
2872 ROSMENUITEMINFO ItemInfo
;
2874 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2875 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2880 MenuInitRosMenuItemInfo(&ItemInfo
);
2881 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2883 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2886 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2888 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2889 return ItemInfo
.hSubMenu
;
2892 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2896 /***********************************************************************
2899 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2901 static LRESULT FASTCALL
2902 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2904 ROSMENUINFO TopMenuInfo
;
2905 ROSMENUINFO MenuInfo
;
2907 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2909 return (LRESULT
) FALSE
;
2912 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2913 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2915 MDINEXTMENU NextMenu
;
2920 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2921 NextMenu
.hmenuNext
= NULL
;
2922 NextMenu
.hwndNext
= NULL
;
2923 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2925 TRACE("%p [%p] -> %p [%p]\n",
2926 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2928 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2930 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2931 NewWnd
= Mt
->OwnerWnd
;
2932 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2934 /* switch to the menu bar */
2936 if (0 != (Style
& WS_CHILD
)
2937 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2944 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2948 Id
= MenuInfo
.MenuItemCount
- 1;
2951 else if (0 != (Style
& WS_SYSMENU
))
2953 /* switch to the system menu */
2954 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2961 else /* application returned a new menu to switch to */
2963 NewMenu
= NextMenu
.hmenuNext
;
2964 NewWnd
= NextMenu
.hwndNext
;
2966 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2968 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2970 if (0 != (Style
& WS_SYSMENU
)
2971 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2973 /* get the real system menu */
2974 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2976 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2978 /* FIXME: Not sure what to do here;
2979 * perhaps try to track NewMenu as a popup? */
2981 WARN(" -- got confused.\n");
2991 if (NewMenu
!= Mt
->TopMenu
)
2993 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2995 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2997 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
3001 if (NewWnd
!= Mt
->OwnerWnd
)
3003 Mt
->OwnerWnd
= NewWnd
;
3004 SetCapture(Mt
->OwnerWnd
);
3005 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
3008 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3009 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3011 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3020 /***********************************************************************
3023 * The idea is not to show the popup if the next input message is
3024 * going to hide it anyway.
3026 static BOOL FASTCALL
3027 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
3031 Msg
.hwnd
= Mt
->OwnerWnd
;
3033 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3034 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
3039 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3040 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
3042 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3043 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3044 if (WM_KEYDOWN
== Msg
.message
3045 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
3047 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3054 /* failures go through this */
3055 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3060 /***********************************************************************
3063 * Handle a VK_ESCAPE key event in a menu.
3065 static BOOL FASTCALL
3066 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3068 BOOL EndMenu
= TRUE
;
3069 ROSMENUINFO MenuInfo
;
3070 HMENU MenuTmp
, MenuPrev
;
3072 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3074 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3075 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
3077 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3079 /* close topmost popup */
3080 while (MenuTmp
!= Mt
->CurrentMenu
)
3083 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3086 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3088 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
3090 Mt
->CurrentMenu
= MenuPrev
;
3098 /***********************************************************************
3101 * Handle a VK_LEFT key event in a menu.
3103 static void FASTCALL
3104 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3106 ROSMENUINFO MenuInfo
;
3107 ROSMENUINFO TopMenuInfo
;
3108 ROSMENUINFO PrevMenuInfo
;
3109 HMENU MenuTmp
, MenuPrev
;
3112 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3114 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3119 /* Try to move 1 column left (if possible) */
3120 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3122 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3124 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3129 /* close topmost popup */
3130 while (MenuTmp
!= Mt
->CurrentMenu
)
3133 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3136 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3140 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
3141 Mt
->CurrentMenu
= MenuPrev
;
3143 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3147 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3149 /* move menu bar selection if no more popups are left */
3151 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
3153 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3156 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3158 /* A sublevel menu was displayed - display the next one
3159 * unless there is another displacement coming up */
3161 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3162 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3164 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3171 /***********************************************************************
3174 * Handle a VK_RIGHT key event in a menu.
3176 static void FASTCALL
3177 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3180 ROSMENUINFO MenuInfo
;
3181 ROSMENUINFO CurrentMenuInfo
;
3184 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3185 Mt
->CurrentMenu
, Mt
->TopMenu
);
3187 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3191 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3193 /* If already displaying a popup, try to display sub-popup */
3195 MenuTmp
= Mt
->CurrentMenu
;
3196 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3198 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3201 /* if subpopup was displayed then we are done */
3202 if (MenuTmp
!= Mt
->CurrentMenu
)
3208 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3213 /* Check to see if there's another column */
3214 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3216 TRACE("Going to %d.\n", NextCol
);
3217 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3219 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3224 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3226 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3228 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3229 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3236 /* try to move to the next item */
3237 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
3239 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3242 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3244 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3245 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3247 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3254 /***********************************************************************
3257 * Find the menu item selected by a key press.
3258 * Return item id, -1 if none, -2 if we should close the menu.
3260 static UINT FASTCALL
3261 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
3262 WCHAR Key
, BOOL ForceMenuChar
)
3264 ROSMENUINFO SysMenuInfo
;
3265 PROSMENUITEMINFO Items
, ItemInfo
;
3269 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
3271 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
3273 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
3275 MenuInfo
= &SysMenuInfo
;
3283 if (NULL
!= MenuInfo
)
3285 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
3289 if (! ForceMenuChar
)
3291 Key
= toupperW(Key
);
3293 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
3295 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
3297 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
3300 p
= strchrW(p
+ 2, '&');
3302 while (NULL
!= p
&& L
'&' == p
[1]);
3303 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
3311 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
3312 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
3313 if (2 == HIWORD(MenuChar
))
3315 return LOWORD(MenuChar
);
3317 if (1 == HIWORD(MenuChar
))
3326 /***********************************************************************
3329 * Menu tracking code.
3332 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3333 HWND Wnd
, const RECT
*Rect
)
3336 ROSMENUINFO MenuInfo
;
3337 ROSMENUITEMINFO ItemInfo
;
3339 INT ExecutedMenuId
= -1;
3341 BOOL EnterIdleSent
= FALSE
;
3344 Mt
.CurrentMenu
= Menu
;
3350 TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3351 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3352 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3355 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3360 if (0 != (Flags
& TPM_BUTTONDOWN
))
3362 /* Get the result in order to start the tracking or not */
3363 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3364 fEndMenu
= ! fRemove
;
3367 SetCapture(Mt
.OwnerWnd
);
3368 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
.OwnerWnd
);
3372 /* we have to keep the message in the queue until it's
3373 * clear that menu loop is not over yet. */
3377 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3379 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3383 /* remove the message from the queue */
3384 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3388 if (! EnterIdleSent
)
3390 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3391 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3392 EnterIdleSent
= TRUE
;
3393 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3399 /* check if EndMenu() tried to cancel us, by posting this message */
3400 if (WM_CANCELMODE
== Msg
.message
)
3402 /* we are now out of the loop */
3405 /* remove the message from the queue */
3406 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3408 /* break out of internal loop, ala ESCAPE */
3412 TranslateMessage(&Msg
);
3415 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3417 EnterIdleSent
= FALSE
;
3421 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3424 * Use the mouse coordinates in lParam instead of those in the MSG
3425 * struct to properly handle synthetic messages. They are already
3426 * in screen coordinates.
3428 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3429 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3431 /* Find a menu for this mouse event */
3432 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3436 /* no WM_NC... messages in captured state */
3438 case WM_RBUTTONDBLCLK
:
3439 case WM_RBUTTONDOWN
:
3440 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3445 case WM_LBUTTONDBLCLK
:
3446 case WM_LBUTTONDOWN
:
3447 /* If the message belongs to the menu, removes it from the queue */
3448 /* Else, end menu tracking */
3449 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3450 fEndMenu
= ! fRemove
;
3454 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3460 /* Check if a menu was selected by the mouse */
3463 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3465 /* End the loop if ExecutedMenuId is an item ID */
3466 /* or if the job was done (ExecutedMenuId = 0). */
3467 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3471 /* No menu was selected by the mouse */
3472 /* if the function was called by TrackPopupMenu, continue
3473 with the menu tracking. If not, stop it */
3474 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3481 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3485 } /* switch(Msg.message) - mouse */
3487 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3489 fRemove
= TRUE
; /* Keyboard messages are always removed */
3501 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3503 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3509 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3511 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3512 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3516 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3517 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3519 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3521 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3523 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3527 else /* otherwise try to move selection */
3529 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3535 MenuKeyLeft(&Mt
, Flags
);
3539 MenuKeyRight(&Mt
, Flags
);
3543 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3549 hi
.cbSize
= sizeof(HELPINFO
);
3550 hi
.iContextType
= HELPINFO_MENUITEM
;
3551 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3553 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3559 MenuInitRosMenuItemInfo(&ItemInfo
);
3560 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3561 MenuInfo
.FocusedItem
,
3564 hi
.iCtrlId
= ItemInfo
.wID
;
3570 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3573 hi
.hItemHandle
= Menu
;
3574 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3575 hi
.MousePos
= Msg
.pt
;
3576 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3583 break; /* WM_KEYDOWN */
3590 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3594 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3596 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3597 fEndMenu
= (ExecutedMenuId
!= -2);
3601 /* Hack to avoid control chars. */
3602 /* We will find a better way real soon... */
3603 if (Msg
.wParam
< 32)
3608 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3609 LOWORD(Msg
.wParam
), FALSE
);
3610 if ((UINT
) -2 == Pos
)
3614 else if ((UINT
) -1 == Pos
)
3620 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3621 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3622 fEndMenu
= (-2 != ExecutedMenuId
);
3626 } /* switch(msg.message) - kbd */
3630 PeekMessageW( &Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3631 DispatchMessageW(&Msg
);
3640 /* finally remove message from the queue */
3642 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3644 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3648 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3652 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3653 SetCapture(NULL
); /* release the capture */
3655 /* If dropdown is still painted and the close box is clicked on
3656 then the menu will be destroyed as part of the DispatchMessage above.
3657 This will then invalidate the menu handle in Mt.hTopMenu. We should
3658 check for this first. */
3659 if (IsMenu(Mt
.TopMenu
))
3661 if (IsWindow(Mt
.OwnerWnd
))
3663 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3665 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3667 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3669 DestroyWindow(MenuInfo
.Wnd
);
3670 MenuInfo
.Wnd
= NULL
;
3672 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3675 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3678 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3680 /* Reset the variable for hiding menu */
3681 MenuInfo
.TimeToHide
= FALSE
;
3682 MenuSetRosMenuInfo(&MenuInfo
);
3686 /* The return value is only used by TrackPopupMenu */
3687 if (!(Flags
& TPM_RETURNCMD
)) return TRUE
;
3688 if (ExecutedMenuId
< 0) ExecutedMenuId
= 0;
3689 return ExecutedMenuId
;
3692 /***********************************************************************
3695 static BOOL FASTCALL
3696 MenuExitTracking(HWND Wnd
)
3698 TRACE("hwnd=%p\n", Wnd
);
3700 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3707 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3709 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3710 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3712 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, Pt
.x
, Pt
.y
);
3716 /* map point to parent client coordinates */
3717 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3718 if (Parent
!= GetDesktopWindow())
3720 ScreenToClient(Parent
, &Pt
);
3723 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3724 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3725 MenuExitTracking(Wnd
);
3731 MenuTrackKbdMenuBar(HWND hWnd
, UINT wParam
, WCHAR wChar
)
3733 UINT uItem
= NO_SELECTED_ITEM
;
3735 ROSMENUINFO MenuInfo
;
3736 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3738 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd
, wParam
, wChar
);
3740 /* find window that has a menu */
3742 while (!((GetWindowLongPtrW( hWnd
, GWL_STYLE
) &
3743 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3744 if (!(hWnd
= GetAncestor( hWnd
, GA_PARENT
))) return;
3746 /* check if we have to track a system menu */
3748 hTrackMenu
= GetMenu( hWnd
);
3749 if (!hTrackMenu
|| IsIconic(hWnd
) || wChar
== ' ' )
3751 if (!(GetWindowLongPtrW( hWnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3752 hTrackMenu
= NtUserGetSystemMenu(hWnd
, FALSE
);
3754 wParam
|= HTSYSMENU
; /* prevent item lookup */
3757 if (!IsMenu( hTrackMenu
)) return;
3759 MenuInitTracking( hWnd
, hTrackMenu
, FALSE
, wFlags
);
3761 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3766 if( wChar
&& wChar
!= ' ' )
3768 uItem
= MenuFindItemByKey( hWnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3769 if ( uItem
>= (UINT
)(-2) )
3771 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3772 /* schedule end of menu tracking */
3773 wFlags
|= TF_ENDMENU
;
3778 MenuSelectItem( hWnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3780 if (wParam
& HTSYSMENU
)
3782 /* prevent sysmenu activation for managed windows on Alt down/up */
3783 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3784 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3788 if( uItem
== NO_SELECTED_ITEM
)
3789 MenuMoveSelection( hWnd
, &MenuInfo
, ITEM_NEXT
);
3791 PostMessageW( hWnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3795 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hWnd
, NULL
);
3796 MenuExitTracking( hWnd
);
3802 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3803 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3805 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3807 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3808 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3809 * MFT_STRING is replaced by MIIM_STRING.
3810 * (So, I guess we should use MIIM_STRING only for strings?)
3812 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3814 * Based on wine, SetMenuItemInfo_common:
3815 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3816 * it will result in a error.
3817 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3818 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3825 LPMENUITEMINFOW mii
,
3832 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3834 if(Flags
& MF_BITMAP
)
3836 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3837 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3839 if (Flags
& MF_HELP
)
3841 /* increase ident */
3842 mii
->fType
|= MF_HELP
;
3845 else if(Flags
& MF_OWNERDRAW
)
3847 mii
->fType
|= MFT_OWNERDRAW
;
3848 mii
->fMask
|= MIIM_DATA
;
3849 mii
->dwItemData
= (DWORD
) NewItem
;
3851 else if (Flags
& MF_SEPARATOR
)
3853 mii
->fType
|= MFT_SEPARATOR
;
3854 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3855 Flags
|= MF_GRAYED
|MF_DISABLED
;
3857 else /* Default action MF_STRING. */
3859 /* Item beginning with a backspace is a help item */
3860 if (NewItem
!= NULL
)
3864 if (*NewItem
== '\b')
3866 mii
->fType
|= MF_HELP
;
3872 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3873 if (*NewItemA
== '\b')
3875 mii
->fType
|= MF_HELP
;
3877 NewItem
= (LPCWSTR
) NewItemA
;
3881 if (Flags
& MF_HELP
)
3882 mii
->fType
|= MF_HELP
;
3883 mii
->fMask
|= MIIM_STRING
;
3884 mii
->fType
|= MFT_STRING
; /* Zero */
3885 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3887 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3889 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3893 mii
->fType
|= MFT_SEPARATOR
;
3894 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3895 Flags
|= MF_GRAYED
|MF_DISABLED
;
3899 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3901 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3904 if(Flags
& MF_MENUBREAK
)
3906 mii
->fType
|= MFT_MENUBREAK
;
3908 else if(Flags
& MF_MENUBARBREAK
)
3910 mii
->fType
|= MFT_MENUBARBREAK
;
3913 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3915 if (Flags
& MF_GRAYED
)
3916 mii
->fState
|= MF_GRAYED
;
3918 if (Flags
& MF_DISABLED
)
3919 mii
->fState
|= MF_DISABLED
;
3921 mii
->fMask
|= MIIM_STATE
;
3923 else if (Flags
& MF_HILITE
)
3925 mii
->fState
|= MF_HILITE
;
3926 mii
->fMask
|= MIIM_STATE
;
3928 else /* default state */
3930 mii
->fState
|= MFS_ENABLED
;
3931 mii
->fMask
|= MIIM_STATE
;
3934 if(Flags
& MF_POPUP
)
3936 mii
->fType
|= MF_POPUP
;
3937 mii
->fMask
|= MIIM_SUBMENU
;
3938 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3942 mii
->fMask
|= MIIM_ID
;
3943 mii
->wID
= (UINT
)IDNewItem
;
3949 /* FUNCTIONS *****************************************************************/
3952 MenuIsStringItem(ULONG TypeData)
3954 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3962 AppendMenuA(HMENU hMenu
,
3964 UINT_PTR uIDNewItem
,
3967 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3976 AppendMenuW(HMENU hMenu
,
3978 UINT_PTR uIDNewItem
,
3981 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3990 CheckMenuItem(HMENU hmenu
,
3994 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3999 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
4002 PROSMENUITEMINFO Items
= NULL
;
4003 UINT cChecked
, cUnchecked
;
4007 if(idFirst
> idLast
)
4010 ItemCount
= GetMenuItemCount(hMenu
);
4012 //mi.cbSize = sizeof(ROSMENUINFO);
4013 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
4016 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
4018 ERR("MenuGetAllRosMenuItemInfo failed\n");
4022 cChecked
= cUnchecked
= 0;
4024 for (i
= 0 ; i
< ItemCount
; i
++)
4027 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
4028 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
4030 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
4032 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
4035 if (uFlags
& MF_BYPOSITION
)
4037 if (i
< idFirst
|| i
> idLast
)
4052 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
4055 if (Items
[i
].wID
== idCheck
)
4069 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4072 Items
[i
].fType
|= MFT_RADIOCHECK
;
4073 Items
[i
].fState
|= MFS_CHECKED
;
4077 Items
[i
].fState
&= ~MFS_CHECKED
;
4080 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4082 ERR("MenuSetRosMenuItemInfo failed\n");
4087 HeapFree(GetProcessHeap(), 0, Items
);
4089 *pChecked
+= cChecked
;
4090 *pUnchecked
+= cUnchecked
;
4092 if (cChecked
|| cUnchecked
)
4102 CheckMenuRadioItem(HMENU hmenu
,
4109 UINT cUnchecked
= 0;
4110 UINT cMenuChanged
= 0;
4112 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4115 if (cMenuChanged
> 1)
4122 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4125 return (cChecked
!= 0);
4136 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4144 CreatePopupMenu(VOID
)
4147 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4155 DrawMenuBar(HWND hWnd
)
4157 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4158 ROSMENUINFO MenuInfo
;
4160 hMenu
= GetMenu(hWnd
);
4163 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4164 MenuInfo
.Height
= 0; // make sure to recalc size
4165 MenuSetRosMenuInfo(&MenuInfo
);
4166 /* The wine method doesn't work and I suspect it's more effort
4167 then hackfix solution
4168 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4169 SWP_NOZORDER | SWP_FRAMECHANGED );
4172 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4181 EnableMenuItem(HMENU hMenu
,
4185 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4195 guii
.cbSize
= sizeof(GUITHREADINFO
);
4196 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4198 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4210 return NtUserGetMenu(hWnd
);
4218 GetMenuCheckMarkDimensions(VOID
)
4220 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4221 GetSystemMetrics(SM_CYMENUCHECK
)));
4229 GetMenuDefaultItem(HMENU hMenu
,
4233 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4241 GetMenuInfo(HMENU hmenu
,
4247 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4250 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4251 mi
.cbSize
= sizeof(MENUINFO
);
4252 mi
.fMask
= lpcmi
->fMask
;
4254 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4256 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4265 GetMenuItemCount(HMENU Menu
)
4267 ROSMENUINFO MenuInfo
;
4269 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4277 GetMenuItemID(HMENU hMenu
,
4280 ROSMENUITEMINFO mii
;
4282 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4283 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4285 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4290 if (NULL
!= mii
.hSubMenu
)
4311 LPMENUITEMINFOA mii
)
4317 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4318 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4320 SetLastError(ERROR_INVALID_PARAMETER
);
4324 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4326 /* No text requested, just pass on */
4327 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4330 AnsiBuffer
= mii
->dwTypeData
;
4331 Count
= miiW
.cch
= mii
->cch
;
4332 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4333 miiW
.dwTypeData
= 0;
4337 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4338 miiW
.cch
* sizeof(WCHAR
));
4339 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4340 miiW
.dwTypeData
[0] = 0;
4343 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4345 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4349 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4351 if (!AnsiBuffer
|| !Count
)
4353 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4354 mii
->dwTypeData
= AnsiBuffer
;
4355 mii
->cch
= miiW
.cch
;
4359 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4363 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4367 if (Count
> miiW
.cch
)
4369 AnsiBuffer
[miiW
.cch
] = 0;
4371 mii
->cch
= mii
->cch
;
4379 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4380 mii
->dwTypeData
= AnsiBuffer
;
4394 LPMENUITEMINFOW mii
)
4400 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4401 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4403 SetLastError(ERROR_INVALID_PARAMETER
);
4407 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4409 /* No text requested, just pass on */
4410 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4413 String
= mii
->dwTypeData
;
4415 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4416 miiW
.dwTypeData
= 0;
4420 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4421 miiW
.cch
* sizeof(WCHAR
));
4422 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4423 miiW
.dwTypeData
[0] = 0;
4426 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4428 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4432 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4434 if (!String
|| !Count
)
4436 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4437 mii
->dwTypeData
= String
; // may not be zero.
4438 mii
->cch
= miiW
.cch
;
4442 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4444 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4447 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4448 mii
->dwTypeData
= String
;
4449 mii
->cch
= strlenW(String
);
4464 ROSMENUINFO MenuInfo
;
4465 ROSMENUITEMINFO mii
;
4466 memset( &mii
, 0, sizeof(mii
) );
4467 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4468 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4471 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4476 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4480 nSubItems
= MenuInfo
.MenuItemCount
;
4482 /* FIXME - ported from wine, does that work (0xff)? */
4483 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4484 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4486 return (UINT
)-1; /* Invalid submenu */
4489 /* FIXME - ported from wine, does that work? */
4490 return (mii
.fType
| mii
.fState
);
4510 memset( &mii
, 0, sizeof(mii
) );
4511 mii
.dwTypeData
= lpString
;
4512 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4513 mii
.fType
= MFT_STRING
;
4514 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4515 mii
.cch
= nMaxCount
;
4517 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4537 memset( &miiW
, 0, sizeof(miiW
) );
4538 miiW
.dwTypeData
= lpString
;
4539 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4540 miiW
.fType
= MFT_STRING
;
4541 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4542 miiW
.cch
= nMaxCount
;
4544 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4562 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4563 mi
.fMask
= MIIM_SUBMENU
;
4565 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4567 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4584 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4586 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4599 UINT_PTR uIDNewItem
,
4603 memset( &mii
, 0, sizeof(mii
) );
4604 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4605 mii
.fMask
= MIIM_FTYPE
;
4607 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4610 (LPCWSTR
) lpNewItem
,
4613 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4627 LPCMENUITEMINFOA lpmii
)
4630 UNICODE_STRING MenuText
;
4632 BOOL CleanHeap
= FALSE
;
4635 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4636 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4638 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4640 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4642 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4645 /* copy the text string */
4646 if (((mi
.fMask
& MIIM_STRING
) ||
4647 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4648 && mi
.dwTypeData
!= NULL
)
4650 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4651 if (!NT_SUCCESS (Status
))
4653 SetLastError (RtlNtStatusToDosError(Status
));
4656 mi
.dwTypeData
= MenuText
.Buffer
;
4657 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4660 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4662 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4677 LPCMENUITEMINFOW lpmii
)
4680 UNICODE_STRING MenuText
;
4683 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4684 if a bad user passes bad data, we crash his process instead of the
4687 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4688 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4690 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4692 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4694 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4697 /* copy the text string */
4698 if (((mi
.fMask
& MIIM_STRING
) ||
4699 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4700 && mi
.dwTypeData
!= NULL
)
4702 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4703 mi
.dwTypeData
= MenuText
.Buffer
;
4704 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4706 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4721 UINT_PTR uIDNewItem
,
4725 memset( &mii
, 0, sizeof(mii
) );
4726 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4727 mii
.fMask
= MIIM_FTYPE
;
4729 MenuSetItemData( &mii
,
4735 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4747 ROSMENUINFO MenuInfo
;
4749 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4757 LoadMenuA(HINSTANCE hInstance
,
4760 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4761 if (Resource
== NULL
)
4765 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4773 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4775 return(LoadMenuIndirectW(lpMenuTemplate
));
4783 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4786 WORD version
, offset
;
4787 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4789 version
= GET_WORD(p
);
4794 case 0: /* standard format is version of 0 */
4795 offset
= GET_WORD(p
);
4796 p
+= sizeof(WORD
) + offset
;
4797 if (!(hMenu
= CreateMenu())) return 0;
4798 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4804 case 1: /* extended format is version of 1 */
4805 offset
= GET_WORD(p
);
4806 p
+= sizeof(WORD
) + offset
;
4807 if (!(hMenu
= CreateMenu())) return 0;
4808 if (!MENUEX_ParseResource(p
, hMenu
))
4810 DestroyMenu( hMenu
);
4815 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4825 LoadMenuW(HINSTANCE hInstance
,
4828 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4829 if (Resource
== NULL
)
4833 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4847 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4860 UINT_PTR uIDNewItem
,
4864 ROSMENUITEMINFO rmii
;
4866 memset( &mii
, 0, sizeof(mii
) );
4867 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4868 mii
.fMask
= MIIM_FTYPE
;
4870 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4874 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4876 MenuInitRosMenuItemInfo( &rmii
);
4878 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4880 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4881 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4883 MenuCleanupRosMenuItemInfo( &rmii
);
4885 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4888 (LPCWSTR
) lpNewItem
,
4891 return SetMenuItemInfoA( hMnu
,
4893 (BOOL
)(MF_BYPOSITION
& uFlags
),
4907 UINT_PTR uIDNewItem
,
4911 ROSMENUITEMINFO rmii
;
4913 memset ( &mii
, 0, sizeof(mii
) );
4914 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4915 mii
.fMask
= MIIM_FTYPE
;
4917 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4919 mi
.Height
= 0; // Force size recalculation.
4921 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4923 MenuInitRosMenuItemInfo( &rmii
);
4925 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4927 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4928 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4930 MenuCleanupRosMenuItemInfo( &rmii
);
4932 /* Init new data for this menu item */
4933 MenuSetItemData( &mii
,
4939 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4940 return SetMenuItemInfoW( hMnu
,
4942 (BOOL
)(MF_BYPOSITION
& uFlags
),
4954 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4969 if(lpcmi
->cbSize
!= sizeof(MENUINFO
))
4972 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4973 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4986 HBITMAP hBitmapUnchecked
,
4987 HBITMAP hBitmapChecked
)
4989 ROSMENUITEMINFO uItem
;
4990 memset ( &uItem
, 0, sizeof(uItem
) );
4991 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4993 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4994 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4996 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4998 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
5000 else /* Install new bitmaps */
5002 uItem
.hbmpChecked
= hBitmapChecked
;
5003 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5004 uItem
.fState
|= MF_USECHECKBITMAPS
;
5006 return NtUserMenuItemInfo(hMenu
, uPosition
,
5007 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
5020 LPCMENUITEMINFOA lpmii
)
5022 MENUITEMINFOW MenuItemInfoW
;
5023 UNICODE_STRING UnicodeString
;
5025 ULONG Result
= FALSE
;
5027 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5029 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5031 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5032 MenuItemInfoW
.hbmpItem
= NULL
;
5035 * MIIM_STRING == good
5036 * MIIM_TYPE & MFT_STRING == good
5037 * MIIM_STRING & MFT_STRING == good
5038 * MIIM_STRING & MFT_OWNERSRAW == good
5040 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5041 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5042 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5043 && MenuItemInfoW
.dwTypeData
!= NULL
)
5045 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5046 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5047 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5048 if (!NT_SUCCESS (Status
))
5050 SetLastError (RtlNtStatusToDosError(Status
));
5053 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5054 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5058 UnicodeString
.Buffer
= NULL
;
5061 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5062 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5064 if (UnicodeString
.Buffer
!= NULL
)
5066 RtlFreeUnicodeString(&UnicodeString
);
5082 LPCMENUITEMINFOW lpmii
)
5084 MENUITEMINFOW MenuItemInfoW
;
5087 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5089 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5091 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5092 MenuItemInfoW
.hbmpItem
= NULL
;
5095 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5096 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5097 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5098 && MenuItemInfoW
.dwTypeData
!= NULL
)
5100 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5102 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5103 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5119 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5124 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5127 return NtUserSetSystemMenu(hwnd
, hMenu
);
5147 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
5149 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
5150 if (0 == (Flags
& TPM_NONOTIFY
))
5152 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5155 if (MenuShowPopup(Wnd
, Menu
, 0, x
, y
, 0, 0 ))
5157 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5159 MenuExitTracking(Wnd
);
5178 /* Not fully implemented */
5179 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5180 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5184 // Example for the Win32/User32 rewrite.
5185 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5199 return NtUserTrackPopupMenuEx( Menu
,
5204 NULL
); // LPTPMPARAMS is null
5213 GetMenuContextHelpId(HMENU hmenu
)
5216 mi
.cbSize
= sizeof(ROSMENUINFO
);
5217 mi
.fMask
= MIM_HELPID
;
5219 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5221 return mi
.dwContextHelpID
;
5242 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5245 Result
= (ULONG_PTR
)lResult
;
5250 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5270 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5273 Result
= (ULONG_PTR
)lResult
;
5278 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5289 LPCWSTR lpszNewItem
,
5294 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5295 for MF_DELETE. We should check the parameters for all others
5296 MF_* actions also (anybody got a doc on ChangeMenu?).
5299 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5302 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5305 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5308 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5311 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5312 flags
&~ MF_REMOVE
);
5314 default : /* MF_INSERT */
5315 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5332 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5333 for MF_DELETE. We should check the parameters for all others
5334 MF_* actions also (anybody got a doc on ChangeMenu?).
5337 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5340 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5343 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5346 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5349 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5350 flags
&~ MF_REMOVE
);
5352 default : /* MF_INSERT */
5353 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);