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 PWND 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
);
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));
1001 case WM_PRINTCLIENT
:
1003 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1004 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1012 /* zero out global pointer in case resident popup window was destroyed. */
1013 if (Wnd
== TopPopup
)
1022 if (0 == GetWindowLongPtrA(Wnd
, 0))
1024 OutputDebugStringA("no menu to display\n");
1029 SetWindowLongPtrA(Wnd
, 0, 0);
1033 case MM_SETMENUHANDLE
:
1034 SetWindowLongPtrA(Wnd
, 0, wParam
);
1037 case MM_GETMENUHANDLE
:
1038 return GetWindowLongPtrA(Wnd
, 0);
1041 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1047 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1049 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1055 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1056 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1060 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1061 return MA_NOACTIVATE
;
1066 BeginPaint(Wnd
, &ps
);
1067 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1072 case WM_PRINTCLIENT
:
1074 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1075 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1083 /* zero out global pointer in case resident popup window was destroyed. */
1084 if (Wnd
== TopPopup
)
1093 if (0 == GetWindowLongPtrW(Wnd
, 0))
1095 OutputDebugStringA("no menu to display\n");
1100 SetWindowLongPtrW(Wnd
, 0, 0);
1104 case MM_SETMENUHANDLE
:
1105 SetWindowLongPtrW(Wnd
, 0, wParam
);
1108 case MM_GETMENUHANDLE
:
1109 return GetWindowLongPtrW(Wnd
, 0);
1112 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1118 /**********************************************************************
1119 * MENUEX_ParseResource
1121 * Parse an extended menu resource and add items to the menu.
1122 * Return a pointer to the end of the resource.
1124 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
1126 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1134 mii
.cbSize
= sizeof(mii
);
1135 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
1136 mii
.fType
= GET_DWORD(res
);
1137 res
+= sizeof(DWORD
);
1138 mii
.fState
= GET_DWORD(res
);
1139 res
+= sizeof(DWORD
);
1140 mii
.wID
= GET_DWORD(res
);
1141 res
+= sizeof(DWORD
);
1142 resinfo
= GET_WORD(res
);
1143 res
+= sizeof(WORD
);
1144 /* Align the text on a word boundary. */
1145 res
+= (~((int)res
- 1)) & 1;
1146 mii
.dwTypeData
= (LPWSTR
) res
;
1147 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1148 /* Align the following fields on a dword boundary. */
1149 res
+= (~((int)res
- 1)) & 3;
1151 if (resinfo
& 1) /* Pop-up? */
1153 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1154 res
+= sizeof(DWORD
);
1155 mii
.hSubMenu
= CreatePopupMenu();
1158 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1160 DestroyMenu(mii
.hSubMenu
);
1163 mii
.fMask
|= MIIM_SUBMENU
;
1164 mii
.fType
|= MF_POPUP
;
1165 mii
.wID
= (UINT
) mii
.hSubMenu
;
1167 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1169 mii
.fType
|= MF_SEPARATOR
;
1171 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1173 while (!(resinfo
& MF_END
));
1178 /**********************************************************************
1179 * MENU_ParseResource
1181 * Parse a standard menu resource and add items to the menu.
1182 * Return a pointer to the end of the resource.
1184 * NOTE: flags is equivalent to the mtOption field
1186 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1195 flags
= GET_WORD(res
);
1197 /* remove MF_END flag before passing it to AppendMenu()! */
1198 end
= (flags
& MF_END
);
1199 if(end
) flags
^= MF_END
;
1201 res
+= sizeof(WORD
);
1202 if(!(flags
& MF_POPUP
))
1205 res
+= sizeof(WORD
);
1209 res
+= strlen(str
) + 1;
1211 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1212 if (flags
& MF_POPUP
)
1214 hSubMenu
= CreatePopupMenu();
1215 if(!hSubMenu
) return NULL
;
1216 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1219 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1221 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1223 else /* Not a popup */
1226 flags
= MF_SEPARATOR
;
1228 if (flags
& MF_SEPARATOR
)
1230 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1231 flags
|= MF_GRAYED
| MF_DISABLED
;
1235 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1237 AppendMenuW(hMenu
, flags
, id
,
1238 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1247 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1249 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
1250 LRESULT Result
= (LRESULT
)hmenu
;
1251 MENUINFO menuinfo
= {0};
1252 MENUITEMINFOW info
= {0};
1254 // removing space for checkboxes from menu
1255 menuinfo
.cbSize
= sizeof(menuinfo
);
1256 menuinfo
.fMask
= MIM_STYLE
;
1257 GetMenuInfo(hmenu
, &menuinfo
);
1258 menuinfo
.dwStyle
|= MNS_NOCHECK
;
1259 SetMenuInfo(hmenu
, &menuinfo
);
1261 // adding bitmaps to menu items
1262 info
.cbSize
= sizeof(info
);
1263 info
.fMask
|= MIIM_BITMAP
;
1264 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
1265 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
1266 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
1267 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
1268 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
1269 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
1270 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
1271 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
1273 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1280 NONCLIENTMETRICSW ncm
;
1282 /* get the menu font */
1283 if(!hMenuFont
|| !hMenuFontBold
)
1285 ncm
.cbSize
= sizeof(ncm
);
1286 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1288 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1292 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1293 if(hMenuFont
== NULL
)
1295 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1299 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1300 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1301 if(hMenuFontBold
== NULL
)
1303 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1304 DeleteObject(hMenuFont
);
1319 DeleteObject(hMenuFont
);
1325 DeleteObject(hMenuFontBold
);
1326 hMenuFontBold
= NULL
;
1332 /***********************************************************************
1335 * Calculate the size of the menu item and store it in ItemInfo->rect.
1337 static void FASTCALL
1338 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, PROSMENUINFO MenuInfo
, HWND WndOwner
,
1339 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1343 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1345 TRACE("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1347 MenuCharSize
.cx
= GdiGetCharDimensions( Dc
, NULL
, &MenuCharSize
.cy
);
1349 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1351 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1354 ** Experimentation under Windows reveals that an owner-drawn
1355 ** menu is expected to return the size of the content part of
1356 ** the menu item, not including the checkmark nor the submenu
1357 ** arrow. Windows adds those values itself and returns the
1358 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1360 MEASUREITEMSTRUCT mis
;
1361 mis
.CtlType
= ODT_MENU
;
1363 mis
.itemID
= ItemInfo
->wID
;
1364 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1365 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1367 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1368 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1369 * width of a menufont character to the width of an owner-drawn menu.
1371 ItemInfo
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1375 /* under at least win95 you seem to be given a standard
1376 height for the menu and the height value is ignored */
1377 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1381 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1384 TRACE("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1388 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1390 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1392 ItemInfo
->Rect
.right
+= CheckBitmapWidth
+ MenuCharSize
.cx
;
1398 if (ItemInfo
->hbmpItem
)
1402 if (!MenuBar
) /* hbmpItem */
1404 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1405 /* Keep the size of the bitmap in callback mode to be able
1406 * to draw it correctly */
1407 ItemInfo
->Rect
.right
= ItemInfo
->Rect
.left
+ Size
.cx
;
1408 if (MenuInfo
->maxBmpSize
.cx
< abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
||
1409 MenuInfo
->maxBmpSize
.cy
< abs(Size
.cy
))
1411 MenuInfo
->maxBmpSize
.cx
= abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
;
1412 MenuInfo
->maxBmpSize
.cy
= abs(Size
.cy
);
1414 MenuSetRosMenuInfo(MenuInfo
);
1415 itemheight
= Size
.cy
+ 2;
1417 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1418 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1419 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1420 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1421 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1423 else /* hbmpItem & MenuBar */
1425 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1426 ItemInfo
->Rect
.right
+= Size
.cx
;
1427 if( ItemInfo
->Text
) ItemInfo
->Rect
.right
+= 2;
1428 itemheight
= Size
.cy
;
1430 /* Special case: Minimize button doesn't have a space behind it. */
1431 if (ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1432 ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1433 ItemInfo
->Rect
.right
-= 1;
1438 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1439 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1440 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1441 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1442 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1445 /* it must be a text item - unless it's the system menu */
1446 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && ItemInfo
->Text
)
1448 HFONT hfontOld
= NULL
;
1449 RECT rc
= ItemInfo
->Rect
;
1450 LONG txtheight
, txtwidth
;
1452 if ( ItemInfo
->fState
& MFS_DEFAULT
)
1454 hfontOld
= SelectObject( Dc
, hMenuFontBold
);
1458 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1459 DT_SINGLELINE
|DT_CALCRECT
);
1460 ItemInfo
->Rect
.right
+= rc
.right
- rc
.left
;
1461 itemheight
= max( max( itemheight
, txtheight
),
1462 GetSystemMetrics( SM_CYMENU
) - 1);
1463 ItemInfo
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1467 if ((p
= strchrW( ItemInfo
->dwTypeData
, '\t' )) != NULL
)
1471 int n
= (int)( p
- ItemInfo
->dwTypeData
);
1472 /* Item contains a tab (only meaningful in popup menus) */
1473 /* get text size before the tab */
1474 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, n
, &rc
,
1475 DT_SINGLELINE
|DT_CALCRECT
);
1476 txtwidth
= rc
.right
- rc
.left
;
1477 p
+= 1; /* advance past the Tab */
1478 /* get text size after the tab */
1479 tmpheight
= DrawTextW( Dc
, p
, -1, &tmprc
, DT_SINGLELINE
|DT_CALCRECT
);
1480 ItemInfo
->XTab
+= txtwidth
;
1481 txtheight
= max( txtheight
, tmpheight
);
1482 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1483 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1487 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1488 DT_SINGLELINE
|DT_CALCRECT
);
1489 txtwidth
= rc
.right
- rc
.left
;
1490 ItemInfo
->XTab
+= txtwidth
;
1492 ItemInfo
->Rect
.right
+= 2 + txtwidth
;
1493 itemheight
= max( itemheight
, max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1495 if (hfontOld
) SelectObject (Dc
, hfontOld
);
1499 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1501 ItemInfo
->Rect
.bottom
+= itemheight
;
1502 TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1505 /***********************************************************************
1506 * MenuPopupMenuCalcSize
1508 * Calculate the size of a popup menu.
1510 static void FASTCALL
1511 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1513 ROSMENUITEMINFO ItemInfo
;
1516 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1518 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1519 if (0 == MenuInfo
->MenuItemCount
)
1521 MenuSetRosMenuInfo(MenuInfo
);
1526 SelectObject(Dc
, hMenuFont
);
1531 MenuInfo
->maxBmpSize
.cx
= 0;
1532 MenuInfo
->maxBmpSize
.cy
= 0;
1534 MenuInitRosMenuItemInfo(&ItemInfo
);
1535 while (Start
< MenuInfo
->MenuItemCount
)
1540 MaxTab
= MaxTabWidth
= 0;
1542 /* Parse items until column break or end of menu */
1543 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1545 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1547 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1548 MenuSetRosMenuInfo(MenuInfo
);
1552 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1556 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1557 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1559 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1560 MenuSetRosMenuInfo(MenuInfo
);
1563 // Not sure here,, The patch from wine removes this.
1564 // if (0 != (ItemInfo.fType & MF_MENUBARBREAK))
1568 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1569 OrgY
= ItemInfo
.Rect
.bottom
;
1570 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1572 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1573 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1577 /* Finish the column (set all items to the largest width found) */
1578 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1581 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1583 ItemInfo
.Rect
.right
= MaxX
;
1584 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1586 ItemInfo
.XTab
= MaxTab
;
1588 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1592 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1595 MenuInfo
->Width
= MaxX
;
1597 /* space for 3d border */
1598 MenuInfo
->Height
+= 2;
1599 MenuInfo
->Width
+= 2;
1601 ReleaseDC(NULL
, Dc
);
1602 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1603 MenuSetRosMenuInfo(MenuInfo
);
1606 /***********************************************************************
1607 * MenuMenuBarCalcSize
1609 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1610 * height is off by 1 pixel which causes lengthy window relocations when
1611 * active document window is maximized/restored.
1613 * Calculate the size of the menu bar.
1615 static void FASTCALL
1616 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1618 ROSMENUITEMINFO ItemInfo
;
1619 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1621 if (NULL
== Rect
|| NULL
== MenuInfo
)
1625 if (0 == MenuInfo
->MenuItemCount
)
1630 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1631 Rect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1632 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1633 MenuInfo
->Height
= 0;
1634 MaxY
= Rect
->top
+ 1;
1638 MenuInfo
->maxBmpSize
.cx
= 0;
1639 MenuInfo
->maxBmpSize
.cy
= 0;
1641 MenuInitRosMenuItemInfo(&ItemInfo
);
1642 while (Start
< MenuInfo
->MenuItemCount
)
1644 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1646 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1652 /* Parse items until line break or end of menu */
1653 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1655 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1660 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1665 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1666 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1667 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1669 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1673 if (ItemInfo
.Rect
.right
> Rect
->right
)
1681 ItemInfo
.Rect
.right
= Rect
->right
;
1684 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1685 OrgX
= ItemInfo
.Rect
.right
;
1686 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1688 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1690 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1696 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1697 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1699 /* Finish the line (set all items to the largest height found) */
1702 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1704 ItemInfo
.Rect
.bottom
= MaxY
;
1705 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1710 Start
= i
; /* This works! */
1714 Rect
->bottom
= MaxY
;
1715 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1716 MenuSetRosMenuInfo(MenuInfo
);
1720 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1721 /* the last item (if several lines, only move the last line) */
1722 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1724 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1727 OrgY
= ItemInfo
.Rect
.top
;
1729 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1735 if (ItemInfo
.Rect
.top
!= OrgY
)
1737 break; /* Other line */
1739 if (OrgX
<= ItemInfo
.Rect
.right
)
1741 break; /* Too far right already */
1743 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1744 ItemInfo
.Rect
.right
= OrgX
;
1745 OrgX
= ItemInfo
.Rect
.left
;
1746 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1747 if (HelpPos
+ 1 <= i
&&
1748 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1750 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1756 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1759 /***********************************************************************
1760 * DrawMenuBarTemp (USER32.@)
1764 * called by W98SE desk.cpl Control Panel Applet
1766 * Not 100% sure about the param names, but close.
1771 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1773 ROSMENUINFO MenuInfo
;
1774 ROSMENUITEMINFO ItemInfo
;
1776 HFONT FontOld
= NULL
;
1777 BOOL flat_menu
= FALSE
;
1779 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1783 Menu
= GetMenu(Wnd
);
1791 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1793 return GetSystemMetrics(SM_CYMENU
);
1796 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1798 FontOld
= SelectObject(DC
, Font
);
1800 if (0 == MenuInfo
.Height
)
1802 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1805 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1807 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
1809 SelectObject(DC
, GetStockObject(DC_PEN
));
1810 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
1811 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1812 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1814 if (0 == MenuInfo
.MenuItemCount
)
1816 SelectObject(DC
, FontOld
);
1817 return GetSystemMetrics(SM_CYMENU
);
1820 MenuInitRosMenuItemInfo(&ItemInfo
);
1821 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1823 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1825 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1826 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1829 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1831 SelectObject(DC
, FontOld
);
1833 return MenuInfo
.Height
;
1837 /***********************************************************************
1840 * Paint a menu bar. Returns the height of the menu bar.
1841 * called from [windows/nonclient.c]
1843 UINT
MenuDrawMenuBar(HDC DC
, LPRECT Rect
, HWND Wnd
, BOOL SuppressDraw
)
1845 ROSMENUINFO MenuInfo
;
1846 HFONT FontOld
= NULL
;
1847 HMENU Menu
= GetMenu(Wnd
);
1849 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1851 return GetSystemMetrics(SM_CYMENU
);
1856 FontOld
= SelectObject(DC
, hMenuFont
);
1858 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1860 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1862 if (NULL
!= FontOld
)
1864 SelectObject(DC
, FontOld
);
1866 return MenuInfo
.Height
;
1870 return DrawMenuBarTemp(Wnd
, DC
, Rect
, Menu
, NULL
);
1874 /***********************************************************************
1877 static BOOL FASTCALL
1878 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1880 TRACE("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1884 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1885 if (0 == (Flags
& TPM_NONOTIFY
))
1887 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1890 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1892 if (0 == (Flags
& TPM_NONOTIFY
))
1894 ROSMENUINFO MenuInfo
;
1896 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1898 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
1900 if (0 == MenuInfo
.Height
)
1902 /* app changed/recreated menu bar entries in WM_INITMENU
1903 Recalculate menu sizes else clicks will not work */
1904 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1905 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1908 /* This makes the menus of applications built with Delphi work.
1909 * It also enables menus to be displayed in more than one window,
1910 * but there are some bugs left that need to be fixed in this case.
1912 if(MenuInfo
.Self
== Menu
)
1915 MenuSetRosMenuInfo(&MenuInfo
);
1923 /***********************************************************************
1926 * Display a popup menu.
1928 static BOOL FASTCALL
1929 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1930 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1932 ROSMENUINFO MenuInfo
;
1933 ROSMENUITEMINFO ItemInfo
;
1936 TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1937 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1939 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1944 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1946 MenuInitRosMenuItemInfo(&ItemInfo
);
1947 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1949 ItemInfo
.fMask
|= MIIM_STATE
;
1950 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1951 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1953 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1954 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1957 /* store the owner for DrawItem */
1958 MenuInfo
.WndOwner
= WndOwner
;
1959 MenuSetRosMenuInfo(&MenuInfo
);
1961 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1963 /* adjust popup menu pos so that it fits within the desktop */
1965 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1966 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1968 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1970 if (0 != XAnchor
&& X
>= Width
- XAnchor
)
1972 X
-= Width
- XAnchor
;
1974 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1976 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1984 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1986 if (0 != YAnchor
&& Y
>= Height
+ YAnchor
)
1988 Y
-= Height
+ YAnchor
;
1990 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1992 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
2001 /* NOTE: In Windows, top menu popup is not owned. */
2002 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
2003 WS_POPUP
, X
, Y
, Width
, Height
,
2004 WndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(WndOwner
, GWLP_HINSTANCE
),
2005 (LPVOID
) MenuInfo
.Self
);
2006 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
2010 if (NULL
== TopPopup
)
2012 TopPopup
= MenuInfo
.Wnd
;
2015 /* Display the window */
2016 SetWindowPos(MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
2017 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2018 UpdateWindow(MenuInfo
.Wnd
);
2023 /***********************************************************************
2026 * Find a Sub menu. Return the position of the submenu, and modifies
2027 * *hmenu in case it is found in another sub-menu.
2028 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
2030 static UINT FASTCALL
2031 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
2033 ROSMENUINFO MenuInfo
;
2034 ROSMENUITEMINFO ItemInfo
;
2039 if ((HMENU
) 0xffff == *Menu
2040 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
2042 return NO_SELECTED_ITEM
;
2045 MenuInitRosMenuItemInfo(&ItemInfo
);
2046 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2048 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2050 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2051 return NO_SELECTED_ITEM
;
2053 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2057 if (ItemInfo
.hSubMenu
== SubTarget
)
2059 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2062 SubMenu
= ItemInfo
.hSubMenu
;
2063 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
2064 if (NO_SELECTED_ITEM
!= Pos
)
2070 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2072 return NO_SELECTED_ITEM
;
2075 /***********************************************************************
2078 static void FASTCALL
2079 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
2080 BOOL SendMenuSelect
, HMENU TopMenu
)
2083 ROSMENUITEMINFO ItemInfo
;
2084 ROSMENUINFO TopMenuInfo
;
2087 TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
2089 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
2094 if (MenuInfo
->FocusedItem
== Index
)
2099 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2101 Dc
= GetDC(MenuInfo
->Wnd
);
2105 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2108 if (NULL
== TopPopup
)
2110 TopPopup
= MenuInfo
->Wnd
;
2113 SelectObject(Dc
, hMenuFont
);
2114 MenuInitRosMenuItemInfo(&ItemInfo
);
2115 /* Clear previous highlighted item */
2116 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2118 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2120 ItemInfo
.fMask
|= MIIM_STATE
;
2121 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2122 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2124 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
2125 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2129 /* Highlight new item (if any) */
2130 MenuInfo
->FocusedItem
= Index
;
2131 MenuSetRosMenuInfo(MenuInfo
);
2132 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2134 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2136 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2138 ItemInfo
.fMask
|= MIIM_STATE
;
2139 ItemInfo
.fState
|= MF_HILITE
;
2140 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2141 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
2142 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2147 SendMessageW(WndOwner
, WM_MENUSELECT
,
2148 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
2149 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
2150 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
2154 else if (SendMenuSelect
)
2156 if (NULL
!= TopMenu
)
2158 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
2159 if (NO_SELECTED_ITEM
!= Pos
)
2161 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
2162 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
2164 SendMessageW(WndOwner
, WM_MENUSELECT
,
2165 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
2167 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
2173 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2174 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2177 /***********************************************************************
2180 * Moves currently selected item according to the Offset parameter.
2181 * If there is no selection then it should select the last item if
2182 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2184 static void FASTCALL
2185 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2188 ROSMENUITEMINFO ItemInfo
;
2191 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2193 /* Prevent looping */
2194 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
2196 else if (Offset
< -1)
2198 else if (Offset
> 1)
2201 MenuInitRosMenuItemInfo(&ItemInfo
);
2203 OrigPos
= MenuInfo
->FocusedItem
;
2204 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2211 i
= MenuInfo
->FocusedItem
;
2218 /* Clip and wrap around */
2221 i
= MenuInfo
->MenuItemCount
- 1;
2223 else if (i
>= MenuInfo
->MenuItemCount
)
2227 /* If this is a good candidate; */
2228 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2229 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2231 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2232 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2235 } while (i
!= OrigPos
);
2238 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2241 /***********************************************************************
2242 * MenuInitSysMenuPopup
2244 * Grey the appropriate items in System menu.
2247 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2255 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2256 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2257 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2258 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2259 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2260 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2261 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2262 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2263 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2264 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2265 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2267 /* The menu item must keep its state if it's disabled */
2270 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2273 /* Set default menu item */
2274 if(Style
& WS_MINIMIZE
)
2276 DefItem
= SC_RESTORE
;
2280 if(HitTest
== HTCAPTION
)
2282 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2290 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2291 mii
.fMask
|= MIIM_STATE
;
2292 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2293 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2298 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2301 /***********************************************************************
2304 * Display the sub-menu of the selected item of this menu.
2305 * Return the handle of the submenu, or menu if no submenu to display.
2307 static HMENU FASTCALL
2308 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2310 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2312 ROSMENUITEMINFO ItemInfo
;
2313 ROSMENUINFO SubMenuInfo
;
2317 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2319 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2321 return MenuInfo
->Self
;
2324 MenuInitRosMenuItemInfo(&ItemInfo
);
2325 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2327 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2328 return MenuInfo
->Self
;
2330 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2332 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2333 return MenuInfo
->Self
;
2336 /* message must be sent before using item,
2337 because nearly everything may be changed by the application ! */
2339 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2340 if (0 == (Flags
& TPM_NONOTIFY
))
2342 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2343 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2346 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2348 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2349 return MenuInfo
->Self
;
2351 Rect
= ItemInfo
.Rect
;
2353 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2354 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2356 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2358 Dc
= GetDC(MenuInfo
->Wnd
);
2362 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2365 SelectObject(Dc
, hMenuFont
);
2366 ItemInfo
.fMask
|= MIIM_STATE
;
2367 ItemInfo
.fState
|= MF_HILITE
;
2368 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2369 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2370 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2371 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2374 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2375 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2377 ItemInfo
.Rect
= Rect
;
2380 ItemInfo
.fMask
|= MIIM_STATE
;
2381 ItemInfo
.fState
|= MF_MOUSESELECT
;
2382 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2384 if (IS_SYSTEM_MENU(MenuInfo
))
2386 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2387 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2389 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2390 Rect
.top
= Rect
.bottom
;
2391 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2392 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2396 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2397 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2399 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2400 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2401 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2402 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2403 - GetSystemMetrics(SM_CYBORDER
);
2407 Rect
.left
+= ItemInfo
.Rect
.left
;
2408 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2409 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2410 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2414 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2415 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2416 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2418 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2421 Ret
= ItemInfo
.hSubMenu
;
2422 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2427 /***********************************************************************
2430 * Hide the sub-popup menus of this menu.
2432 static void FASTCALL
2433 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2435 ROSMENUINFO SubMenuInfo
;
2436 ROSMENUITEMINFO ItemInfo
;
2438 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2440 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2442 MenuInitRosMenuItemInfo(&ItemInfo
);
2443 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2444 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2445 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2446 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2448 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2451 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2452 ItemInfo
.fMask
|= MIIM_STATE
;
2453 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2454 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2456 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2457 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2458 DestroyWindow(SubMenuInfo
.Wnd
);
2459 SubMenuInfo
.Wnd
= NULL
;
2460 MenuSetRosMenuInfo(&SubMenuInfo
);
2465 /***********************************************************************
2466 * MenuSwitchTracking
2468 * Helper function for menu navigation routines.
2470 static void FASTCALL
2471 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2473 ROSMENUINFO TopMenuInfo
;
2475 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2477 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2478 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2479 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2481 /* both are top level menus (system and menu-bar) */
2482 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2483 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2484 Mt
->TopMenu
= PtMenuInfo
->Self
;
2488 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2491 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2494 /***********************************************************************
2495 * MenuExecFocusedItem
2497 * Execute a menu item (for instance when user pressed Enter).
2498 * Return the wID of the executed item. Otherwise, -1 indicating
2499 * that no menu item was executed, -2 if a popup is shown;
2500 * Have to receive the flags for the TrackPopupMenu options to avoid
2501 * sending unwanted message.
2505 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2507 ROSMENUITEMINFO ItemInfo
;
2510 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2512 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2517 MenuInitRosMenuItemInfo(&ItemInfo
);
2518 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2520 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2524 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2526 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2528 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2529 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2531 /* If TPM_RETURNCMD is set you return the id, but
2532 do not send a message to the owner */
2533 if (0 == (Flags
& TPM_RETURNCMD
))
2535 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2537 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2538 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2542 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2543 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2544 MenuInfo
->FocusedItem
,
2545 (LPARAM
)MenuInfo
->Self
);
2547 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2551 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2557 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2564 /***********************************************************************
2567 * Return TRUE if we can go on with menu tracking.
2569 static BOOL FASTCALL
2570 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2573 ROSMENUINFO MenuInfo
;
2574 ROSMENUITEMINFO Item
;
2576 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2580 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2584 if (IS_SYSTEM_MENU(&MenuInfo
))
2590 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2592 MenuInitRosMenuItemInfo(&Item
);
2593 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2595 MenuCleanupRosMenuItemInfo(&Item
);
2599 if (!(Item
.fType
& MF_SEPARATOR
) &&
2600 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2602 if (MenuInfo
.FocusedItem
!= Index
)
2604 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2607 /* If the popup menu is not already "popped" */
2608 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2610 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2614 MenuCleanupRosMenuItemInfo(&Item
);
2619 /* else the click was on the menu bar, finish the tracking */
2624 /***********************************************************************
2627 * Return the value of MenuExecFocusedItem if
2628 * the selected item was not a popup. Else open the popup.
2629 * A -1 return value indicates that we go on with menu tracking.
2633 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2636 ROSMENUINFO MenuInfo
;
2637 ROSMENUITEMINFO ItemInfo
;
2639 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2644 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2649 if (! IS_SYSTEM_MENU(&MenuInfo
))
2651 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2653 MenuInitRosMenuItemInfo(&ItemInfo
);
2654 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2655 MenuInfo
.FocusedItem
== Id
)
2657 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2659 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2660 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2661 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2663 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2665 /* If we are dealing with the top-level menu */
2666 /* and this is a click on an already "popped" item: */
2667 /* Stop the menu tracking and close the opened submenus */
2668 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2670 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2674 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2675 MenuInfo
.TimeToHide
= TRUE
;
2676 MenuSetRosMenuInfo(&MenuInfo
);
2682 /***********************************************************************
2685 * Walks menu chain trying to find a menu pt maps to.
2687 static HMENU FASTCALL
2688 MenuPtMenu(HMENU Menu
, POINT Pt
)
2690 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2691 ROSMENUINFO MenuInfo
;
2692 ROSMENUITEMINFO ItemInfo
;
2696 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2701 /* try subpopup first (if any) */
2702 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2704 MenuInitRosMenuItemInfo(&ItemInfo
);
2705 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2706 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2707 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2709 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2712 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2716 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2719 /* check the current window (avoiding WM_HITTEST) */
2720 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2721 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2723 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2728 else if (HTSYSMENU
== Ht
)
2730 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2732 else if (HTMENU
== Ht
)
2734 Ret
= GetMenu(MenuInfo
.Wnd
);
2740 /***********************************************************************
2743 * Return TRUE if we can go on with menu tracking.
2745 static BOOL FASTCALL
2746 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2749 ROSMENUINFO MenuInfo
;
2750 ROSMENUITEMINFO ItemInfo
;
2754 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2758 if (IS_SYSTEM_MENU(&MenuInfo
))
2764 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2769 Index
= NO_SELECTED_ITEM
;
2772 if (NO_SELECTED_ITEM
== Index
)
2774 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2775 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2777 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2781 else if (MenuInfo
.FocusedItem
!= Index
)
2783 MenuInitRosMenuItemInfo(&ItemInfo
);
2784 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2785 !(ItemInfo
.fType
& MF_SEPARATOR
))
2787 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2788 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2789 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2791 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2797 /******************************************************************************
2799 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2801 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2804 PROSMENUITEMINFO MenuItems
;
2806 i
= MenuInfo
->FocusedItem
;
2807 if (NO_SELECTED_ITEM
== i
)
2812 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2814 return NO_SELECTED_ITEM
;
2817 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2819 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2825 return NO_SELECTED_ITEM
;
2828 /******************************************************************************
2830 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2832 static UINT FASTCALL
2833 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2836 PROSMENUITEMINFO MenuItems
;
2838 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2840 return NO_SELECTED_ITEM
;
2843 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2845 return NO_SELECTED_ITEM
;
2848 /* Find the start of the column */
2850 for (i
= MenuInfo
->FocusedItem
;
2851 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2859 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2860 return NO_SELECTED_ITEM
;
2863 for (--i
; 0 != i
; --i
)
2865 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2871 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2872 TRACE("ret %d.\n", i
);
2877 /***********************************************************************
2880 * Return the handle of the selected sub-popup menu (if any).
2882 static HMENU FASTCALL
2883 MenuGetSubPopup(HMENU Menu
)
2885 ROSMENUINFO MenuInfo
;
2886 ROSMENUITEMINFO ItemInfo
;
2888 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2889 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2894 MenuInitRosMenuItemInfo(&ItemInfo
);
2895 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2897 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2900 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2902 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2903 return ItemInfo
.hSubMenu
;
2906 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2910 /***********************************************************************
2913 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2915 static LRESULT FASTCALL
2916 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2918 ROSMENUINFO TopMenuInfo
;
2919 ROSMENUINFO MenuInfo
;
2921 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2923 return (LRESULT
) FALSE
;
2926 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2927 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2929 MDINEXTMENU NextMenu
;
2934 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2935 NextMenu
.hmenuNext
= NULL
;
2936 NextMenu
.hwndNext
= NULL
;
2937 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2939 TRACE("%p [%p] -> %p [%p]\n",
2940 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2942 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2944 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2945 NewWnd
= Mt
->OwnerWnd
;
2946 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2948 /* switch to the menu bar */
2950 if (0 != (Style
& WS_CHILD
)
2951 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2958 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2962 Id
= MenuInfo
.MenuItemCount
- 1;
2965 else if (0 != (Style
& WS_SYSMENU
))
2967 /* switch to the system menu */
2968 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2975 else /* application returned a new menu to switch to */
2977 NewMenu
= NextMenu
.hmenuNext
;
2978 NewWnd
= NextMenu
.hwndNext
;
2980 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2982 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2984 if (0 != (Style
& WS_SYSMENU
)
2985 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2987 /* get the real system menu */
2988 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2990 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2992 /* FIXME: Not sure what to do here;
2993 * perhaps try to track NewMenu as a popup? */
2995 WARN(" -- got confused.\n");
3005 if (NewMenu
!= Mt
->TopMenu
)
3007 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3009 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3011 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
3015 if (NewWnd
!= Mt
->OwnerWnd
)
3017 Mt
->OwnerWnd
= NewWnd
;
3018 SetCapture(Mt
->OwnerWnd
);
3019 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
3022 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3023 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3025 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3034 /***********************************************************************
3037 * The idea is not to show the popup if the next input message is
3038 * going to hide it anyway.
3040 static BOOL FASTCALL
3041 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
3045 Msg
.hwnd
= Mt
->OwnerWnd
;
3047 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3048 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
3053 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3054 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
3056 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3057 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3058 if (WM_KEYDOWN
== Msg
.message
3059 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
3061 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3068 /* failures go through this */
3069 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3074 /***********************************************************************
3077 * Handle a VK_ESCAPE key event in a menu.
3079 static BOOL FASTCALL
3080 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3082 BOOL EndMenu
= TRUE
;
3083 ROSMENUINFO MenuInfo
;
3084 HMENU MenuTmp
, MenuPrev
;
3086 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3088 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3089 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
3091 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3093 /* close topmost popup */
3094 while (MenuTmp
!= Mt
->CurrentMenu
)
3097 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3100 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3102 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
3104 Mt
->CurrentMenu
= MenuPrev
;
3112 /***********************************************************************
3115 * Handle a VK_LEFT key event in a menu.
3117 static void FASTCALL
3118 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3120 ROSMENUINFO MenuInfo
;
3121 ROSMENUINFO TopMenuInfo
;
3122 ROSMENUINFO PrevMenuInfo
;
3123 HMENU MenuTmp
, MenuPrev
;
3126 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3128 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3133 /* Try to move 1 column left (if possible) */
3134 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3136 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3138 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3143 /* close topmost popup */
3144 while (MenuTmp
!= Mt
->CurrentMenu
)
3147 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3150 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3154 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
3155 Mt
->CurrentMenu
= MenuPrev
;
3157 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3161 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3163 /* move menu bar selection if no more popups are left */
3165 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
3167 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3170 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3172 /* A sublevel menu was displayed - display the next one
3173 * unless there is another displacement coming up */
3175 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3176 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3178 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3185 /***********************************************************************
3188 * Handle a VK_RIGHT key event in a menu.
3190 static void FASTCALL
3191 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3194 ROSMENUINFO MenuInfo
;
3195 ROSMENUINFO CurrentMenuInfo
;
3198 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3199 Mt
->CurrentMenu
, Mt
->TopMenu
);
3201 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3205 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3207 /* If already displaying a popup, try to display sub-popup */
3209 MenuTmp
= Mt
->CurrentMenu
;
3210 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3212 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3215 /* if subpopup was displayed then we are done */
3216 if (MenuTmp
!= Mt
->CurrentMenu
)
3222 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3227 /* Check to see if there's another column */
3228 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3230 TRACE("Going to %d.\n", NextCol
);
3231 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3233 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3238 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3240 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3242 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3243 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3250 /* try to move to the next item */
3251 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
3253 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3256 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3258 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3259 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3261 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3268 /***********************************************************************
3271 * Find the menu item selected by a key press.
3272 * Return item id, -1 if none, -2 if we should close the menu.
3274 static UINT FASTCALL
3275 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
3276 WCHAR Key
, BOOL ForceMenuChar
)
3278 ROSMENUINFO SysMenuInfo
;
3279 PROSMENUITEMINFO Items
, ItemInfo
;
3283 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
3285 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
3287 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
3289 MenuInfo
= &SysMenuInfo
;
3297 if (NULL
!= MenuInfo
)
3299 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
3303 if (! ForceMenuChar
)
3305 Key
= toupperW(Key
);
3307 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
3309 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
3311 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
3314 p
= strchrW(p
+ 2, '&');
3316 while (NULL
!= p
&& L
'&' == p
[1]);
3317 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
3325 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
3326 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
3327 if (2 == HIWORD(MenuChar
))
3329 return LOWORD(MenuChar
);
3331 if (1 == HIWORD(MenuChar
))
3340 /***********************************************************************
3343 * Menu tracking code.
3346 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3347 HWND Wnd
, const RECT
*Rect
)
3350 ROSMENUINFO MenuInfo
;
3351 ROSMENUITEMINFO ItemInfo
;
3353 INT ExecutedMenuId
= -1;
3355 BOOL EnterIdleSent
= FALSE
;
3358 Mt
.CurrentMenu
= Menu
;
3364 TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3365 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3366 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3369 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3374 if (0 != (Flags
& TPM_BUTTONDOWN
))
3376 /* Get the result in order to start the tracking or not */
3377 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3378 fEndMenu
= ! fRemove
;
3381 SetCapture(Mt
.OwnerWnd
);
3382 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
.OwnerWnd
);
3386 /* we have to keep the message in the queue until it's
3387 * clear that menu loop is not over yet. */
3391 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3393 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3397 /* remove the message from the queue */
3398 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3402 if (! EnterIdleSent
)
3404 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3405 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3406 EnterIdleSent
= TRUE
;
3407 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3413 /* check if EndMenu() tried to cancel us, by posting this message */
3414 if (WM_CANCELMODE
== Msg
.message
)
3416 /* we are now out of the loop */
3419 /* remove the message from the queue */
3420 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3422 /* break out of internal loop, ala ESCAPE */
3426 TranslateMessage(&Msg
);
3429 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3431 EnterIdleSent
= FALSE
;
3435 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3438 * Use the mouse coordinates in lParam instead of those in the MSG
3439 * struct to properly handle synthetic messages. They are already
3440 * in screen coordinates.
3442 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3443 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3445 /* Find a menu for this mouse event */
3446 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3450 /* no WM_NC... messages in captured state */
3452 case WM_RBUTTONDBLCLK
:
3453 case WM_RBUTTONDOWN
:
3454 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3459 case WM_LBUTTONDBLCLK
:
3460 case WM_LBUTTONDOWN
:
3461 /* If the message belongs to the menu, removes it from the queue */
3462 /* Else, end menu tracking */
3463 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3464 fEndMenu
= ! fRemove
;
3468 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3474 /* Check if a menu was selected by the mouse */
3477 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3479 /* End the loop if ExecutedMenuId is an item ID */
3480 /* or if the job was done (ExecutedMenuId = 0). */
3481 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3485 /* No menu was selected by the mouse */
3486 /* if the function was called by TrackPopupMenu, continue
3487 with the menu tracking. If not, stop it */
3488 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3495 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3499 } /* switch(Msg.message) - mouse */
3501 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3503 fRemove
= TRUE
; /* Keyboard messages are always removed */
3515 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3517 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3523 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3525 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3526 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3530 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3531 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3533 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3535 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3537 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3541 else /* otherwise try to move selection */
3543 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3549 MenuKeyLeft(&Mt
, Flags
);
3553 MenuKeyRight(&Mt
, Flags
);
3557 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3563 hi
.cbSize
= sizeof(HELPINFO
);
3564 hi
.iContextType
= HELPINFO_MENUITEM
;
3565 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3567 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3573 MenuInitRosMenuItemInfo(&ItemInfo
);
3574 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3575 MenuInfo
.FocusedItem
,
3578 hi
.iCtrlId
= ItemInfo
.wID
;
3584 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3587 hi
.hItemHandle
= Menu
;
3588 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3589 hi
.MousePos
= Msg
.pt
;
3590 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3597 break; /* WM_KEYDOWN */
3604 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3608 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3610 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3611 fEndMenu
= (ExecutedMenuId
!= -2);
3615 /* Hack to avoid control chars. */
3616 /* We will find a better way real soon... */
3617 if (Msg
.wParam
< 32)
3622 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3623 LOWORD(Msg
.wParam
), FALSE
);
3624 if ((UINT
) -2 == Pos
)
3628 else if ((UINT
) -1 == Pos
)
3634 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3635 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3636 fEndMenu
= (-2 != ExecutedMenuId
);
3640 } /* switch(msg.message) - kbd */
3644 PeekMessageW( &Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3645 DispatchMessageW(&Msg
);
3654 /* finally remove message from the queue */
3656 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3658 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3662 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3666 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3667 SetCapture(NULL
); /* release the capture */
3669 /* If dropdown is still painted and the close box is clicked on
3670 then the menu will be destroyed as part of the DispatchMessage above.
3671 This will then invalidate the menu handle in Mt.hTopMenu. We should
3672 check for this first. */
3673 if (IsMenu(Mt
.TopMenu
))
3675 if (IsWindow(Mt
.OwnerWnd
))
3677 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3679 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3681 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3683 DestroyWindow(MenuInfo
.Wnd
);
3684 MenuInfo
.Wnd
= NULL
;
3686 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3689 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3692 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3694 /* Reset the variable for hiding menu */
3695 MenuInfo
.TimeToHide
= FALSE
;
3696 MenuSetRosMenuInfo(&MenuInfo
);
3700 /* The return value is only used by TrackPopupMenu */
3701 if (!(Flags
& TPM_RETURNCMD
)) return TRUE
;
3702 if (ExecutedMenuId
< 0) ExecutedMenuId
= 0;
3703 return ExecutedMenuId
;
3706 /***********************************************************************
3709 static BOOL FASTCALL
3710 MenuExitTracking(HWND Wnd
)
3712 TRACE("hwnd=%p\n", Wnd
);
3714 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3721 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3723 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3724 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3726 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, Pt
.x
, Pt
.y
);
3730 /* map point to parent client coordinates */
3731 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3732 if (Parent
!= GetDesktopWindow())
3734 ScreenToClient(Parent
, &Pt
);
3737 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3738 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3739 MenuExitTracking(Wnd
);
3745 MenuTrackKbdMenuBar(HWND hWnd
, UINT wParam
, WCHAR wChar
)
3747 UINT uItem
= NO_SELECTED_ITEM
;
3749 ROSMENUINFO MenuInfo
;
3750 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3752 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd
, wParam
, wChar
);
3754 /* find window that has a menu */
3756 while (!((GetWindowLongPtrW( hWnd
, GWL_STYLE
) &
3757 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3758 if (!(hWnd
= GetAncestor( hWnd
, GA_PARENT
))) return;
3760 /* check if we have to track a system menu */
3762 hTrackMenu
= GetMenu( hWnd
);
3763 if (!hTrackMenu
|| IsIconic(hWnd
) || wChar
== ' ' )
3765 if (!(GetWindowLongPtrW( hWnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3766 hTrackMenu
= NtUserGetSystemMenu(hWnd
, FALSE
);
3768 wParam
|= HTSYSMENU
; /* prevent item lookup */
3771 if (!IsMenu( hTrackMenu
)) return;
3773 MenuInitTracking( hWnd
, hTrackMenu
, FALSE
, wFlags
);
3775 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3780 if( wChar
&& wChar
!= ' ' )
3782 uItem
= MenuFindItemByKey( hWnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3783 if ( uItem
>= (UINT
)(-2) )
3785 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3786 /* schedule end of menu tracking */
3787 wFlags
|= TF_ENDMENU
;
3792 MenuSelectItem( hWnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3794 if (wParam
& HTSYSMENU
)
3796 /* prevent sysmenu activation for managed windows on Alt down/up */
3797 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3798 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3802 if( uItem
== NO_SELECTED_ITEM
)
3803 MenuMoveSelection( hWnd
, &MenuInfo
, ITEM_NEXT
);
3805 PostMessageW( hWnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3809 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hWnd
, NULL
);
3810 MenuExitTracking( hWnd
);
3816 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3817 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3819 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3821 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3822 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3823 * MFT_STRING is replaced by MIIM_STRING.
3824 * (So, I guess we should use MIIM_STRING only for strings?)
3826 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3828 * Based on wine, SetMenuItemInfo_common:
3829 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3830 * it will result in a error.
3831 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3832 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3839 LPMENUITEMINFOW mii
,
3846 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3848 if(Flags
& MF_BITMAP
)
3850 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3851 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3853 if (Flags
& MF_HELP
)
3855 /* increase ident */
3856 mii
->fType
|= MF_HELP
;
3859 else if(Flags
& MF_OWNERDRAW
)
3861 mii
->fType
|= MFT_OWNERDRAW
;
3862 mii
->fMask
|= MIIM_DATA
;
3863 mii
->dwItemData
= (DWORD
) NewItem
;
3865 else if (Flags
& MF_SEPARATOR
)
3867 mii
->fType
|= MFT_SEPARATOR
;
3868 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3869 Flags
|= MF_GRAYED
|MF_DISABLED
;
3871 else /* Default action MF_STRING. */
3873 /* Item beginning with a backspace is a help item */
3874 if (NewItem
!= NULL
)
3878 if (*NewItem
== '\b')
3880 mii
->fType
|= MF_HELP
;
3886 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3887 if (*NewItemA
== '\b')
3889 mii
->fType
|= MF_HELP
;
3891 NewItem
= (LPCWSTR
) NewItemA
;
3895 if (Flags
& MF_HELP
)
3896 mii
->fType
|= MF_HELP
;
3897 mii
->fMask
|= MIIM_STRING
;
3898 mii
->fType
|= MFT_STRING
; /* Zero */
3899 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3901 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3903 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3907 mii
->fType
|= MFT_SEPARATOR
;
3908 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3909 Flags
|= MF_GRAYED
|MF_DISABLED
;
3913 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3915 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3918 if(Flags
& MF_MENUBREAK
)
3920 mii
->fType
|= MFT_MENUBREAK
;
3922 else if(Flags
& MF_MENUBARBREAK
)
3924 mii
->fType
|= MFT_MENUBARBREAK
;
3927 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3929 if (Flags
& MF_GRAYED
)
3930 mii
->fState
|= MF_GRAYED
;
3932 if (Flags
& MF_DISABLED
)
3933 mii
->fState
|= MF_DISABLED
;
3935 mii
->fMask
|= MIIM_STATE
;
3937 else if (Flags
& MF_HILITE
)
3939 mii
->fState
|= MF_HILITE
;
3940 mii
->fMask
|= MIIM_STATE
;
3942 else /* default state */
3944 mii
->fState
|= MFS_ENABLED
;
3945 mii
->fMask
|= MIIM_STATE
;
3948 if(Flags
& MF_POPUP
)
3950 mii
->fType
|= MF_POPUP
;
3951 mii
->fMask
|= MIIM_SUBMENU
;
3952 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3956 mii
->fMask
|= MIIM_ID
;
3957 mii
->wID
= (UINT
)IDNewItem
;
3963 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3965 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3968 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3970 Result
= (LRESULT
)LoadMenuW(Common
->hModule
, (LPCWSTR
)&Common
->MenuName
);
3972 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3976 /* FUNCTIONS *****************************************************************/
3979 MenuIsStringItem(ULONG TypeData)
3981 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3989 AppendMenuA(HMENU hMenu
,
3991 UINT_PTR uIDNewItem
,
3994 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
4003 AppendMenuW(HMENU hMenu
,
4005 UINT_PTR uIDNewItem
,
4008 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
4017 CheckMenuItem(HMENU hmenu
,
4021 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4026 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
4029 PROSMENUITEMINFO Items
= NULL
;
4030 UINT cChecked
, cUnchecked
;
4034 if(idFirst
> idLast
)
4037 ItemCount
= GetMenuItemCount(hMenu
);
4039 //mi.cbSize = sizeof(ROSMENUINFO);
4040 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
4043 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
4045 ERR("MenuGetAllRosMenuItemInfo failed\n");
4049 cChecked
= cUnchecked
= 0;
4051 for (i
= 0 ; i
< ItemCount
; i
++)
4054 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
4055 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
4057 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
4059 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
4062 if (uFlags
& MF_BYPOSITION
)
4064 if (i
< idFirst
|| i
> idLast
)
4079 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
4082 if (Items
[i
].wID
== idCheck
)
4096 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4099 Items
[i
].fType
|= MFT_RADIOCHECK
;
4100 Items
[i
].fState
|= MFS_CHECKED
;
4104 Items
[i
].fState
&= ~MFS_CHECKED
;
4107 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4109 ERR("MenuSetRosMenuItemInfo failed\n");
4114 HeapFree(GetProcessHeap(), 0, Items
);
4116 *pChecked
+= cChecked
;
4117 *pUnchecked
+= cUnchecked
;
4119 if (cChecked
|| cUnchecked
)
4129 CheckMenuRadioItem(HMENU hmenu
,
4136 UINT cUnchecked
= 0;
4137 UINT cMenuChanged
= 0;
4139 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4142 if (cMenuChanged
> 1)
4149 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4152 return (cChecked
!= 0);
4163 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4171 CreatePopupMenu(VOID
)
4174 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4182 DrawMenuBar(HWND hWnd
)
4184 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4185 ROSMENUINFO MenuInfo
;
4187 hMenu
= GetMenu(hWnd
);
4190 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4191 MenuInfo
.Height
= 0; // make sure to recalc size
4192 MenuSetRosMenuInfo(&MenuInfo
);
4193 /* The wine method doesn't work and I suspect it's more effort
4194 then hackfix solution
4195 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4196 SWP_NOZORDER | SWP_FRAMECHANGED );
4199 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4208 EnableMenuItem(HMENU hMenu
,
4212 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4222 guii
.cbSize
= sizeof(GUITHREADINFO
);
4223 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4225 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4237 return NtUserGetMenu(hWnd
);
4245 GetMenuCheckMarkDimensions(VOID
)
4247 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4248 GetSystemMetrics(SM_CYMENUCHECK
)));
4256 GetMenuDefaultItem(HMENU hMenu
,
4260 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4268 GetMenuInfo(HMENU hmenu
,
4274 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4277 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4278 mi
.cbSize
= sizeof(MENUINFO
);
4279 mi
.fMask
= lpcmi
->fMask
;
4281 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4283 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4292 GetMenuItemCount(HMENU Menu
)
4294 ROSMENUINFO MenuInfo
;
4296 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4304 GetMenuItemID(HMENU hMenu
,
4307 ROSMENUITEMINFO mii
;
4309 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4310 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4312 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4317 if (NULL
!= mii
.hSubMenu
)
4338 LPMENUITEMINFOA mii
)
4344 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4345 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4347 SetLastError(ERROR_INVALID_PARAMETER
);
4351 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4353 /* No text requested, just pass on */
4354 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4357 AnsiBuffer
= mii
->dwTypeData
;
4358 Count
= miiW
.cch
= mii
->cch
;
4359 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4360 miiW
.dwTypeData
= 0;
4364 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4365 miiW
.cch
* sizeof(WCHAR
));
4366 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4367 miiW
.dwTypeData
[0] = 0;
4370 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4372 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4376 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4378 if (!AnsiBuffer
|| !Count
)
4380 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4381 mii
->dwTypeData
= AnsiBuffer
;
4382 mii
->cch
= miiW
.cch
;
4386 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4390 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4394 if (Count
> miiW
.cch
)
4396 AnsiBuffer
[miiW
.cch
] = 0;
4398 mii
->cch
= mii
->cch
;
4406 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4407 mii
->dwTypeData
= AnsiBuffer
;
4421 LPMENUITEMINFOW mii
)
4427 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4428 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4430 SetLastError(ERROR_INVALID_PARAMETER
);
4434 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4436 /* No text requested, just pass on */
4437 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4440 String
= mii
->dwTypeData
;
4442 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4443 miiW
.dwTypeData
= 0;
4447 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4448 miiW
.cch
* sizeof(WCHAR
));
4449 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4450 miiW
.dwTypeData
[0] = 0;
4453 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4455 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4459 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4461 if (!String
|| !Count
)
4463 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4464 mii
->dwTypeData
= String
; // may not be zero.
4465 mii
->cch
= miiW
.cch
;
4469 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4471 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4474 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4475 mii
->dwTypeData
= String
;
4476 mii
->cch
= strlenW(String
);
4491 ROSMENUINFO MenuInfo
;
4492 ROSMENUITEMINFO mii
;
4493 memset( &mii
, 0, sizeof(mii
) );
4494 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4495 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4498 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4503 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4507 nSubItems
= MenuInfo
.MenuItemCount
;
4509 /* FIXME - ported from wine, does that work (0xff)? */
4510 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4511 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4513 return (UINT
)-1; /* Invalid submenu */
4516 /* FIXME - ported from wine, does that work? */
4517 return (mii
.fType
| mii
.fState
);
4537 memset( &mii
, 0, sizeof(mii
) );
4538 mii
.dwTypeData
= lpString
;
4539 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4540 mii
.fType
= MFT_STRING
;
4541 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4542 mii
.cch
= nMaxCount
;
4544 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4564 memset( &miiW
, 0, sizeof(miiW
) );
4565 miiW
.dwTypeData
= lpString
;
4566 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4567 miiW
.fType
= MFT_STRING
;
4568 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4569 miiW
.cch
= nMaxCount
;
4571 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4589 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4590 mi
.fMask
= MIIM_SUBMENU
;
4592 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4594 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4611 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4613 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4626 UINT_PTR uIDNewItem
,
4630 memset( &mii
, 0, sizeof(mii
) );
4631 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4632 mii
.fMask
= MIIM_FTYPE
;
4634 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4637 (LPCWSTR
) lpNewItem
,
4640 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4654 LPCMENUITEMINFOA lpmii
)
4657 UNICODE_STRING MenuText
;
4659 BOOL CleanHeap
= FALSE
;
4662 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4663 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4665 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4667 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4669 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4672 /* copy the text string */
4673 if (((mi
.fMask
& MIIM_STRING
) ||
4674 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4675 && mi
.dwTypeData
!= NULL
)
4677 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4678 if (!NT_SUCCESS (Status
))
4680 SetLastError (RtlNtStatusToDosError(Status
));
4683 mi
.dwTypeData
= MenuText
.Buffer
;
4684 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4687 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4689 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4704 LPCMENUITEMINFOW lpmii
)
4707 UNICODE_STRING MenuText
;
4710 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4711 if a bad user passes bad data, we crash his process instead of the
4714 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4715 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4717 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4719 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4721 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4724 /* copy the text string */
4725 if (((mi
.fMask
& MIIM_STRING
) ||
4726 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4727 && mi
.dwTypeData
!= NULL
)
4729 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4730 mi
.dwTypeData
= MenuText
.Buffer
;
4731 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4733 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4748 UINT_PTR uIDNewItem
,
4752 memset( &mii
, 0, sizeof(mii
) );
4753 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4754 mii
.fMask
= MIIM_FTYPE
;
4756 MenuSetItemData( &mii
,
4762 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4774 ROSMENUINFO MenuInfo
;
4776 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4784 LoadMenuA(HINSTANCE hInstance
,
4787 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4788 if (Resource
== NULL
)
4792 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4800 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4802 return(LoadMenuIndirectW(lpMenuTemplate
));
4810 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4813 WORD version
, offset
;
4814 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4816 version
= GET_WORD(p
);
4821 case 0: /* standard format is version of 0 */
4822 offset
= GET_WORD(p
);
4823 p
+= sizeof(WORD
) + offset
;
4824 if (!(hMenu
= CreateMenu())) return 0;
4825 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4831 case 1: /* extended format is version of 1 */
4832 offset
= GET_WORD(p
);
4833 p
+= sizeof(WORD
) + offset
;
4834 if (!(hMenu
= CreateMenu())) return 0;
4835 if (!MENUEX_ParseResource(p
, hMenu
))
4837 DestroyMenu( hMenu
);
4842 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4852 LoadMenuW(HINSTANCE hInstance
,
4855 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4856 if (Resource
== NULL
)
4860 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4874 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4887 UINT_PTR uIDNewItem
,
4891 ROSMENUITEMINFO rmii
;
4893 memset( &mii
, 0, sizeof(mii
) );
4894 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4895 mii
.fMask
= MIIM_FTYPE
;
4897 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4901 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4903 MenuInitRosMenuItemInfo( &rmii
);
4905 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4907 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4908 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4910 MenuCleanupRosMenuItemInfo( &rmii
);
4912 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4915 (LPCWSTR
) lpNewItem
,
4918 return SetMenuItemInfoA( hMnu
,
4920 (BOOL
)(MF_BYPOSITION
& uFlags
),
4934 UINT_PTR uIDNewItem
,
4938 ROSMENUITEMINFO rmii
;
4940 memset ( &mii
, 0, sizeof(mii
) );
4941 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4942 mii
.fMask
= MIIM_FTYPE
;
4944 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4946 mi
.Height
= 0; // Force size recalculation.
4948 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4950 MenuInitRosMenuItemInfo( &rmii
);
4952 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4954 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4955 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4957 MenuCleanupRosMenuItemInfo( &rmii
);
4959 /* Init new data for this menu item */
4960 MenuSetItemData( &mii
,
4966 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4967 return SetMenuItemInfoW( hMnu
,
4969 (BOOL
)(MF_BYPOSITION
& uFlags
),
4981 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4997 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4999 SetLastError(ERROR_INVALID_PARAMETER
);
5003 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5004 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
5017 HBITMAP hBitmapUnchecked
,
5018 HBITMAP hBitmapChecked
)
5020 ROSMENUITEMINFO uItem
;
5021 memset ( &uItem
, 0, sizeof(uItem
) );
5022 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
5024 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
5025 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
5027 if (!hBitmapChecked
&& !hBitmapUnchecked
)
5029 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
5031 else /* Install new bitmaps */
5033 uItem
.hbmpChecked
= hBitmapChecked
;
5034 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5035 uItem
.fState
|= MF_USECHECKBITMAPS
;
5037 return NtUserMenuItemInfo(hMenu
, uPosition
,
5038 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
5051 LPCMENUITEMINFOA lpmii
)
5053 MENUITEMINFOW MenuItemInfoW
;
5054 UNICODE_STRING UnicodeString
;
5056 ULONG Result
= FALSE
;
5058 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5060 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5062 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5063 MenuItemInfoW
.hbmpItem
= NULL
;
5066 * MIIM_STRING == good
5067 * MIIM_TYPE & MFT_STRING == good
5068 * MIIM_STRING & MFT_STRING == good
5069 * MIIM_STRING & MFT_OWNERSRAW == good
5071 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5072 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5073 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5074 && MenuItemInfoW
.dwTypeData
!= NULL
)
5076 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5077 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5078 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5079 if (!NT_SUCCESS (Status
))
5081 SetLastError (RtlNtStatusToDosError(Status
));
5084 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5085 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5089 UnicodeString
.Buffer
= NULL
;
5092 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5093 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5095 if (UnicodeString
.Buffer
!= NULL
)
5097 RtlFreeUnicodeString(&UnicodeString
);
5113 LPCMENUITEMINFOW lpmii
)
5115 MENUITEMINFOW MenuItemInfoW
;
5118 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5120 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5122 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5123 MenuItemInfoW
.hbmpItem
= NULL
;
5126 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5127 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5128 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5129 && MenuItemInfoW
.dwTypeData
!= NULL
)
5131 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5133 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5134 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5150 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5155 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5158 return NtUserSetSystemMenu(hwnd
, hMenu
);
5178 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
5180 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
5181 if (0 == (Flags
& TPM_NONOTIFY
))
5183 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5186 if (MenuShowPopup(Wnd
, Menu
, 0, x
, y
, 0, 0 ))
5188 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5190 MenuExitTracking(Wnd
);
5209 /* Not fully implemented */
5210 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5211 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5215 // Example for the Win32/User32 rewrite.
5216 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5230 return NtUserTrackPopupMenuEx( Menu
,
5235 NULL
); // LPTPMPARAMS is null
5244 GetMenuContextHelpId(HMENU hmenu
)
5247 mi
.cbSize
= sizeof(ROSMENUINFO
);
5248 mi
.fMask
= MIM_HELPID
;
5250 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5252 return mi
.dwContextHelpID
;
5273 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5276 Result
= (ULONG_PTR
)lResult
;
5281 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5301 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5304 Result
= (ULONG_PTR
)lResult
;
5309 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5320 LPCWSTR lpszNewItem
,
5325 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5326 for MF_DELETE. We should check the parameters for all others
5327 MF_* actions also (anybody got a doc on ChangeMenu?).
5330 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5333 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5336 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5339 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5342 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5343 flags
&~ MF_REMOVE
);
5345 default : /* MF_INSERT */
5346 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5363 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5364 for MF_DELETE. We should check the parameters for all others
5365 MF_* actions also (anybody got a doc on ChangeMenu?).
5368 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5371 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5374 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5377 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5380 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5381 flags
&~ MF_REMOVE
);
5383 default : /* MF_INSERT */
5384 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);