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
:
1039 return GetWindowLongPtrA(Wnd
, 0);
1042 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1048 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1050 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1056 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1057 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1061 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1062 return MA_NOACTIVATE
;
1067 BeginPaint(Wnd
, &ps
);
1068 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1073 case WM_PRINTCLIENT
:
1075 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1076 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1084 /* zero out global pointer in case resident popup window was destroyed. */
1085 if (Wnd
== TopPopup
)
1094 if (0 == GetWindowLongPtrW(Wnd
, 0))
1096 OutputDebugStringA("no menu to display\n");
1101 SetWindowLongPtrW(Wnd
, 0, 0);
1105 case MM_SETMENUHANDLE
:
1106 SetWindowLongPtrW(Wnd
, 0, wParam
);
1109 case MM_GETMENUHANDLE
:
1111 return GetWindowLongPtrW(Wnd
, 0);
1114 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1120 /**********************************************************************
1121 * MENUEX_ParseResource
1123 * Parse an extended menu resource and add items to the menu.
1124 * Return a pointer to the end of the resource.
1126 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
1128 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1136 mii
.cbSize
= sizeof(mii
);
1137 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
1138 mii
.fType
= GET_DWORD(res
);
1139 res
+= sizeof(DWORD
);
1140 mii
.fState
= GET_DWORD(res
);
1141 res
+= sizeof(DWORD
);
1142 mii
.wID
= GET_DWORD(res
);
1143 res
+= sizeof(DWORD
);
1144 resinfo
= GET_WORD(res
);
1145 res
+= sizeof(WORD
);
1146 /* Align the text on a word boundary. */
1147 res
+= (~((int)res
- 1)) & 1;
1148 mii
.dwTypeData
= (LPWSTR
) res
;
1149 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1150 /* Align the following fields on a dword boundary. */
1151 res
+= (~((int)res
- 1)) & 3;
1153 if (resinfo
& 1) /* Pop-up? */
1155 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1156 res
+= sizeof(DWORD
);
1157 mii
.hSubMenu
= CreatePopupMenu();
1160 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1162 DestroyMenu(mii
.hSubMenu
);
1165 mii
.fMask
|= MIIM_SUBMENU
;
1166 mii
.fType
|= MF_POPUP
;
1167 mii
.wID
= (UINT
) mii
.hSubMenu
;
1169 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1171 mii
.fType
|= MF_SEPARATOR
;
1173 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1175 while (!(resinfo
& MF_END
));
1180 /**********************************************************************
1181 * MENU_ParseResource
1183 * Parse a standard menu resource and add items to the menu.
1184 * Return a pointer to the end of the resource.
1186 * NOTE: flags is equivalent to the mtOption field
1188 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1197 flags
= GET_WORD(res
);
1199 /* remove MF_END flag before passing it to AppendMenu()! */
1200 end
= (flags
& MF_END
);
1201 if(end
) flags
^= MF_END
;
1203 res
+= sizeof(WORD
);
1204 if(!(flags
& MF_POPUP
))
1207 res
+= sizeof(WORD
);
1211 res
+= strlen(str
) + 1;
1213 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1214 if (flags
& MF_POPUP
)
1216 hSubMenu
= CreatePopupMenu();
1217 if(!hSubMenu
) return NULL
;
1218 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1221 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1223 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1225 else /* Not a popup */
1228 flags
= MF_SEPARATOR
;
1230 if (flags
& MF_SEPARATOR
)
1232 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1233 flags
|= MF_GRAYED
| MF_DISABLED
;
1237 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1239 AppendMenuW(hMenu
, flags
, id
,
1240 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1249 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1251 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
1252 LRESULT Result
= (LRESULT
)hmenu
;
1253 MENUINFO menuinfo
= {0};
1254 MENUITEMINFOW info
= {0};
1256 // removing space for checkboxes from menu
1257 menuinfo
.cbSize
= sizeof(menuinfo
);
1258 menuinfo
.fMask
= MIM_STYLE
;
1259 GetMenuInfo(hmenu
, &menuinfo
);
1260 menuinfo
.dwStyle
|= MNS_NOCHECK
;
1261 SetMenuInfo(hmenu
, &menuinfo
);
1263 // adding bitmaps to menu items
1264 info
.cbSize
= sizeof(info
);
1265 info
.fMask
|= MIIM_BITMAP
;
1266 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
1267 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
1268 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
1269 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
1270 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
1271 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
1272 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
1273 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
1275 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1282 NONCLIENTMETRICSW ncm
;
1284 /* get the menu font */
1285 if(!hMenuFont
|| !hMenuFontBold
)
1287 ncm
.cbSize
= sizeof(ncm
);
1288 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1290 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1294 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1295 if(hMenuFont
== NULL
)
1297 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1301 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1302 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1303 if(hMenuFontBold
== NULL
)
1305 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1306 DeleteObject(hMenuFont
);
1321 DeleteObject(hMenuFont
);
1327 DeleteObject(hMenuFontBold
);
1328 hMenuFontBold
= NULL
;
1334 /***********************************************************************
1337 * Calculate the size of the menu item and store it in ItemInfo->rect.
1339 static void FASTCALL
1340 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, PROSMENUINFO MenuInfo
, HWND WndOwner
,
1341 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1345 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1347 TRACE("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1349 MenuCharSize
.cx
= GdiGetCharDimensions( Dc
, NULL
, &MenuCharSize
.cy
);
1351 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1353 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1356 ** Experimentation under Windows reveals that an owner-drawn
1357 ** menu is expected to return the size of the content part of
1358 ** the menu item, not including the checkmark nor the submenu
1359 ** arrow. Windows adds those values itself and returns the
1360 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1362 MEASUREITEMSTRUCT mis
;
1363 mis
.CtlType
= ODT_MENU
;
1365 mis
.itemID
= ItemInfo
->wID
;
1366 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1367 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1369 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1370 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1371 * width of a menufont character to the width of an owner-drawn menu.
1373 ItemInfo
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1377 /* under at least win95 you seem to be given a standard
1378 height for the menu and the height value is ignored */
1379 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1383 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1386 TRACE("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1390 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1392 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1394 ItemInfo
->Rect
.right
+= CheckBitmapWidth
+ MenuCharSize
.cx
;
1400 if (ItemInfo
->hbmpItem
)
1404 if (!MenuBar
) /* hbmpItem */
1406 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1407 /* Keep the size of the bitmap in callback mode to be able
1408 * to draw it correctly */
1409 ItemInfo
->Rect
.right
= ItemInfo
->Rect
.left
+ Size
.cx
;
1410 if (MenuInfo
->maxBmpSize
.cx
< abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
||
1411 MenuInfo
->maxBmpSize
.cy
< abs(Size
.cy
))
1413 MenuInfo
->maxBmpSize
.cx
= abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
;
1414 MenuInfo
->maxBmpSize
.cy
= abs(Size
.cy
);
1416 MenuSetRosMenuInfo(MenuInfo
);
1417 itemheight
= Size
.cy
+ 2;
1419 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1420 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1421 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1422 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1423 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1425 else /* hbmpItem & MenuBar */
1427 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1428 ItemInfo
->Rect
.right
+= Size
.cx
;
1429 if( ItemInfo
->Text
) ItemInfo
->Rect
.right
+= 2;
1430 itemheight
= Size
.cy
;
1432 /* Special case: Minimize button doesn't have a space behind it. */
1433 if (ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1434 ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1435 ItemInfo
->Rect
.right
-= 1;
1440 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1441 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1442 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1443 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1444 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1447 /* it must be a text item - unless it's the system menu */
1448 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && ItemInfo
->Text
)
1450 HFONT hfontOld
= NULL
;
1451 RECT rc
= ItemInfo
->Rect
;
1452 LONG txtheight
, txtwidth
;
1454 if ( ItemInfo
->fState
& MFS_DEFAULT
)
1456 hfontOld
= SelectObject( Dc
, hMenuFontBold
);
1460 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1461 DT_SINGLELINE
|DT_CALCRECT
);
1462 ItemInfo
->Rect
.right
+= rc
.right
- rc
.left
;
1463 itemheight
= max( max( itemheight
, txtheight
),
1464 GetSystemMetrics( SM_CYMENU
) - 1);
1465 ItemInfo
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1469 if ((p
= strchrW( ItemInfo
->dwTypeData
, '\t' )) != NULL
)
1473 int n
= (int)( p
- ItemInfo
->dwTypeData
);
1474 /* Item contains a tab (only meaningful in popup menus) */
1475 /* get text size before the tab */
1476 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, n
, &rc
,
1477 DT_SINGLELINE
|DT_CALCRECT
);
1478 txtwidth
= rc
.right
- rc
.left
;
1479 p
+= 1; /* advance past the Tab */
1480 /* get text size after the tab */
1481 tmpheight
= DrawTextW( Dc
, p
, -1, &tmprc
, DT_SINGLELINE
|DT_CALCRECT
);
1482 ItemInfo
->XTab
+= txtwidth
;
1483 txtheight
= max( txtheight
, tmpheight
);
1484 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1485 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1489 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1490 DT_SINGLELINE
|DT_CALCRECT
);
1491 txtwidth
= rc
.right
- rc
.left
;
1492 ItemInfo
->XTab
+= txtwidth
;
1494 ItemInfo
->Rect
.right
+= 2 + txtwidth
;
1495 itemheight
= max( itemheight
, max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1497 if (hfontOld
) SelectObject (Dc
, hfontOld
);
1501 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1503 ItemInfo
->Rect
.bottom
+= itemheight
;
1504 TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1507 /***********************************************************************
1508 * MenuPopupMenuCalcSize
1510 * Calculate the size of a popup menu.
1512 static void FASTCALL
1513 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1515 ROSMENUITEMINFO ItemInfo
;
1518 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1520 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1521 if (0 == MenuInfo
->MenuItemCount
)
1523 MenuSetRosMenuInfo(MenuInfo
);
1528 SelectObject(Dc
, hMenuFont
);
1533 MenuInfo
->maxBmpSize
.cx
= 0;
1534 MenuInfo
->maxBmpSize
.cy
= 0;
1536 MenuInitRosMenuItemInfo(&ItemInfo
);
1537 while (Start
< MenuInfo
->MenuItemCount
)
1542 MaxTab
= MaxTabWidth
= 0;
1544 /* Parse items until column break or end of menu */
1545 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1547 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1549 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1550 MenuSetRosMenuInfo(MenuInfo
);
1554 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1558 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1559 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1561 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1562 MenuSetRosMenuInfo(MenuInfo
);
1565 // Not sure here,, The patch from wine removes this.
1566 // if (0 != (ItemInfo.fType & MF_MENUBARBREAK))
1570 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1571 OrgY
= ItemInfo
.Rect
.bottom
;
1572 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1574 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1575 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1579 /* Finish the column (set all items to the largest width found) */
1580 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1583 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1585 ItemInfo
.Rect
.right
= MaxX
;
1586 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1588 ItemInfo
.XTab
= MaxTab
;
1590 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1594 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1597 MenuInfo
->Width
= MaxX
;
1599 /* space for 3d border */
1600 MenuInfo
->Height
+= 2;
1601 MenuInfo
->Width
+= 2;
1603 ReleaseDC(NULL
, Dc
);
1604 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1605 MenuSetRosMenuInfo(MenuInfo
);
1608 /***********************************************************************
1609 * MenuMenuBarCalcSize
1611 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1612 * height is off by 1 pixel which causes lengthy window relocations when
1613 * active document window is maximized/restored.
1615 * Calculate the size of the menu bar.
1617 static void FASTCALL
1618 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1620 ROSMENUITEMINFO ItemInfo
;
1621 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1623 if (NULL
== Rect
|| NULL
== MenuInfo
)
1627 if (0 == MenuInfo
->MenuItemCount
)
1632 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1633 Rect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1634 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1635 MenuInfo
->Height
= 0;
1636 MaxY
= Rect
->top
+ 1;
1640 MenuInfo
->maxBmpSize
.cx
= 0;
1641 MenuInfo
->maxBmpSize
.cy
= 0;
1643 MenuInitRosMenuItemInfo(&ItemInfo
);
1644 while (Start
< MenuInfo
->MenuItemCount
)
1646 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1648 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1654 /* Parse items until line break or end of menu */
1655 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1657 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1662 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1667 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1668 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1669 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1671 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1675 if (ItemInfo
.Rect
.right
> Rect
->right
)
1683 ItemInfo
.Rect
.right
= Rect
->right
;
1686 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1687 OrgX
= ItemInfo
.Rect
.right
;
1688 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1690 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1692 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1698 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1699 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1701 /* Finish the line (set all items to the largest height found) */
1704 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1706 ItemInfo
.Rect
.bottom
= MaxY
;
1707 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1712 Start
= i
; /* This works! */
1716 Rect
->bottom
= MaxY
;
1717 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1718 MenuSetRosMenuInfo(MenuInfo
);
1722 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1723 /* the last item (if several lines, only move the last line) */
1724 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1726 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1729 OrgY
= ItemInfo
.Rect
.top
;
1731 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1737 if (ItemInfo
.Rect
.top
!= OrgY
)
1739 break; /* Other line */
1741 if (OrgX
<= ItemInfo
.Rect
.right
)
1743 break; /* Too far right already */
1745 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1746 ItemInfo
.Rect
.right
= OrgX
;
1747 OrgX
= ItemInfo
.Rect
.left
;
1748 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1749 if (HelpPos
+ 1 <= i
&&
1750 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1752 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1758 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1761 /***********************************************************************
1762 * DrawMenuBarTemp (USER32.@)
1766 * called by W98SE desk.cpl Control Panel Applet
1768 * Not 100% sure about the param names, but close.
1773 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1775 ROSMENUINFO MenuInfo
;
1776 ROSMENUITEMINFO ItemInfo
;
1778 HFONT FontOld
= NULL
;
1779 BOOL flat_menu
= FALSE
;
1781 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1785 Menu
= GetMenu(Wnd
);
1793 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1795 return GetSystemMetrics(SM_CYMENU
);
1798 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1800 FontOld
= SelectObject(DC
, Font
);
1802 if (0 == MenuInfo
.Height
)
1804 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1807 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1809 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
1811 SelectObject(DC
, GetStockObject(DC_PEN
));
1812 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
1813 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1814 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1816 if (0 == MenuInfo
.MenuItemCount
)
1818 SelectObject(DC
, FontOld
);
1819 return GetSystemMetrics(SM_CYMENU
);
1822 MenuInitRosMenuItemInfo(&ItemInfo
);
1823 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1825 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1827 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1828 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1831 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1833 SelectObject(DC
, FontOld
);
1835 return MenuInfo
.Height
;
1839 /***********************************************************************
1842 * Paint a menu bar. Returns the height of the menu bar.
1843 * called from [windows/nonclient.c]
1845 UINT
MenuDrawMenuBar(HDC DC
, LPRECT Rect
, HWND Wnd
, BOOL SuppressDraw
)
1847 ROSMENUINFO MenuInfo
;
1848 HFONT FontOld
= NULL
;
1849 HMENU Menu
= GetMenu(Wnd
);
1851 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1853 return GetSystemMetrics(SM_CYMENU
);
1858 FontOld
= SelectObject(DC
, hMenuFont
);
1860 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1862 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1864 if (NULL
!= FontOld
)
1866 SelectObject(DC
, FontOld
);
1868 return MenuInfo
.Height
;
1872 return DrawMenuBarTemp(Wnd
, DC
, Rect
, Menu
, NULL
);
1876 /***********************************************************************
1879 static BOOL FASTCALL
1880 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1882 TRACE("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1886 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1887 if (0 == (Flags
& TPM_NONOTIFY
))
1889 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1892 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1894 if (0 == (Flags
& TPM_NONOTIFY
))
1896 ROSMENUINFO MenuInfo
;
1898 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1900 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
1902 if (0 == MenuInfo
.Height
)
1904 /* app changed/recreated menu bar entries in WM_INITMENU
1905 Recalculate menu sizes else clicks will not work */
1906 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1907 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1910 /* This makes the menus of applications built with Delphi work.
1911 * It also enables menus to be displayed in more than one window,
1912 * but there are some bugs left that need to be fixed in this case.
1914 if(MenuInfo
.Self
== Menu
)
1917 MenuSetRosMenuInfo(&MenuInfo
);
1925 /***********************************************************************
1928 * Display a popup menu.
1930 static BOOL FASTCALL
1931 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1932 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1934 ROSMENUINFO MenuInfo
;
1935 ROSMENUITEMINFO ItemInfo
;
1938 TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1939 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1941 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1946 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1948 MenuInitRosMenuItemInfo(&ItemInfo
);
1949 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1951 ItemInfo
.fMask
|= MIIM_STATE
;
1952 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1953 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1955 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1956 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1959 /* store the owner for DrawItem */
1960 MenuInfo
.WndOwner
= WndOwner
;
1961 MenuSetRosMenuInfo(&MenuInfo
);
1963 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1965 /* adjust popup menu pos so that it fits within the desktop */
1967 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1968 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1970 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1972 if (0 != XAnchor
&& X
>= Width
- XAnchor
)
1974 X
-= Width
- XAnchor
;
1976 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1978 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1986 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1988 if (0 != YAnchor
&& Y
>= Height
+ YAnchor
)
1990 Y
-= Height
+ YAnchor
;
1992 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1994 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
2003 /* NOTE: In Windows, top menu popup is not owned. */
2004 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
2005 WS_POPUP
, X
, Y
, Width
, Height
,
2006 WndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(WndOwner
, GWLP_HINSTANCE
),
2007 (LPVOID
) MenuInfo
.Self
);
2008 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
2012 if (NULL
== TopPopup
)
2014 TopPopup
= MenuInfo
.Wnd
;
2017 /* Display the window */
2018 SetWindowPos(MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
2019 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2020 UpdateWindow(MenuInfo
.Wnd
);
2025 /***********************************************************************
2028 * Find a Sub menu. Return the position of the submenu, and modifies
2029 * *hmenu in case it is found in another sub-menu.
2030 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
2032 static UINT FASTCALL
2033 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
2035 ROSMENUINFO MenuInfo
;
2036 ROSMENUITEMINFO ItemInfo
;
2041 if ((HMENU
) 0xffff == *Menu
2042 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
2044 return NO_SELECTED_ITEM
;
2047 MenuInitRosMenuItemInfo(&ItemInfo
);
2048 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2050 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2052 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2053 return NO_SELECTED_ITEM
;
2055 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2059 if (ItemInfo
.hSubMenu
== SubTarget
)
2061 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2064 SubMenu
= ItemInfo
.hSubMenu
;
2065 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
2066 if (NO_SELECTED_ITEM
!= Pos
)
2072 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2074 return NO_SELECTED_ITEM
;
2077 /***********************************************************************
2080 static void FASTCALL
2081 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
2082 BOOL SendMenuSelect
, HMENU TopMenu
)
2085 ROSMENUITEMINFO ItemInfo
;
2086 ROSMENUINFO TopMenuInfo
;
2089 TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
2091 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
2096 if (MenuInfo
->FocusedItem
== Index
)
2101 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2103 Dc
= GetDC(MenuInfo
->Wnd
);
2107 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2110 if (NULL
== TopPopup
)
2112 TopPopup
= MenuInfo
->Wnd
;
2115 SelectObject(Dc
, hMenuFont
);
2116 MenuInitRosMenuItemInfo(&ItemInfo
);
2117 /* Clear previous highlighted item */
2118 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2120 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2122 ItemInfo
.fMask
|= MIIM_STATE
;
2123 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2124 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2126 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
2127 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2131 /* Highlight new item (if any) */
2132 MenuInfo
->FocusedItem
= Index
;
2133 MenuSetRosMenuInfo(MenuInfo
);
2134 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2136 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2138 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2140 ItemInfo
.fMask
|= MIIM_STATE
;
2141 ItemInfo
.fState
|= MF_HILITE
;
2142 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2143 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
2144 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2149 SendMessageW(WndOwner
, WM_MENUSELECT
,
2150 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
2151 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
2152 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
2156 else if (SendMenuSelect
)
2158 if (NULL
!= TopMenu
)
2160 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
2161 if (NO_SELECTED_ITEM
!= Pos
)
2163 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
2164 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
2166 SendMessageW(WndOwner
, WM_MENUSELECT
,
2167 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
2169 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
2175 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2176 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2179 /***********************************************************************
2182 * Moves currently selected item according to the Offset parameter.
2183 * If there is no selection then it should select the last item if
2184 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2186 static void FASTCALL
2187 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2190 ROSMENUITEMINFO ItemInfo
;
2193 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2195 /* Prevent looping */
2196 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
2198 else if (Offset
< -1)
2200 else if (Offset
> 1)
2203 MenuInitRosMenuItemInfo(&ItemInfo
);
2205 OrigPos
= MenuInfo
->FocusedItem
;
2206 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2213 i
= MenuInfo
->FocusedItem
;
2220 /* Clip and wrap around */
2223 i
= MenuInfo
->MenuItemCount
- 1;
2225 else if (i
>= MenuInfo
->MenuItemCount
)
2229 /* If this is a good candidate; */
2230 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2231 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2233 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2234 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2237 } while (i
!= OrigPos
);
2240 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2243 /***********************************************************************
2244 * MenuInitSysMenuPopup
2246 * Grey the appropriate items in System menu.
2249 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2257 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2258 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2259 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2260 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2261 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2262 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2263 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2264 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2265 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2266 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2267 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2269 /* The menu item must keep its state if it's disabled */
2272 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2275 /* Set default menu item */
2276 if(Style
& WS_MINIMIZE
)
2278 DefItem
= SC_RESTORE
;
2282 if(HitTest
== HTCAPTION
)
2284 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2292 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2293 mii
.fMask
|= MIIM_STATE
;
2294 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2295 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2300 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2303 /***********************************************************************
2306 * Display the sub-menu of the selected item of this menu.
2307 * Return the handle of the submenu, or menu if no submenu to display.
2309 static HMENU FASTCALL
2310 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2312 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2314 ROSMENUITEMINFO ItemInfo
;
2315 ROSMENUINFO SubMenuInfo
;
2319 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2321 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2323 return MenuInfo
->Self
;
2326 MenuInitRosMenuItemInfo(&ItemInfo
);
2327 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2329 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2330 return MenuInfo
->Self
;
2332 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2334 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2335 return MenuInfo
->Self
;
2338 /* message must be sent before using item,
2339 because nearly everything may be changed by the application ! */
2341 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2342 if (0 == (Flags
& TPM_NONOTIFY
))
2344 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2345 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2348 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2350 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2351 return MenuInfo
->Self
;
2353 Rect
= ItemInfo
.Rect
;
2355 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2356 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2358 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2360 Dc
= GetDC(MenuInfo
->Wnd
);
2364 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2367 SelectObject(Dc
, hMenuFont
);
2368 ItemInfo
.fMask
|= MIIM_STATE
;
2369 ItemInfo
.fState
|= MF_HILITE
;
2370 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2371 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2372 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2373 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2376 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2377 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2379 ItemInfo
.Rect
= Rect
;
2382 ItemInfo
.fMask
|= MIIM_STATE
;
2383 ItemInfo
.fState
|= MF_MOUSESELECT
;
2384 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2386 if (IS_SYSTEM_MENU(MenuInfo
))
2388 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2389 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2391 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2392 Rect
.top
= Rect
.bottom
;
2393 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2394 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2398 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2399 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2401 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2402 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2403 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2404 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2405 - GetSystemMetrics(SM_CYBORDER
);
2409 Rect
.left
+= ItemInfo
.Rect
.left
;
2410 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2411 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2412 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2416 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2417 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2418 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2420 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2423 Ret
= ItemInfo
.hSubMenu
;
2424 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2429 /***********************************************************************
2432 * Hide the sub-popup menus of this menu.
2434 static void FASTCALL
2435 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2437 ROSMENUINFO SubMenuInfo
;
2438 ROSMENUITEMINFO ItemInfo
;
2440 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2442 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2444 MenuInitRosMenuItemInfo(&ItemInfo
);
2445 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2446 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2447 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2448 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2450 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2453 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2454 ItemInfo
.fMask
|= MIIM_STATE
;
2455 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2456 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2458 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2459 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2460 DestroyWindow(SubMenuInfo
.Wnd
);
2461 SubMenuInfo
.Wnd
= NULL
;
2462 MenuSetRosMenuInfo(&SubMenuInfo
);
2467 /***********************************************************************
2468 * MenuSwitchTracking
2470 * Helper function for menu navigation routines.
2472 static void FASTCALL
2473 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2475 ROSMENUINFO TopMenuInfo
;
2477 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2479 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2480 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2481 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2483 /* both are top level menus (system and menu-bar) */
2484 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2485 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2486 Mt
->TopMenu
= PtMenuInfo
->Self
;
2490 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2493 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2496 /***********************************************************************
2497 * MenuExecFocusedItem
2499 * Execute a menu item (for instance when user pressed Enter).
2500 * Return the wID of the executed item. Otherwise, -1 indicating
2501 * that no menu item was executed, -2 if a popup is shown;
2502 * Have to receive the flags for the TrackPopupMenu options to avoid
2503 * sending unwanted message.
2507 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2509 ROSMENUITEMINFO ItemInfo
;
2512 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2514 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2519 MenuInitRosMenuItemInfo(&ItemInfo
);
2520 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2522 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2526 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2528 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2530 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2531 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2533 /* If TPM_RETURNCMD is set you return the id, but
2534 do not send a message to the owner */
2535 if (0 == (Flags
& TPM_RETURNCMD
))
2537 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2539 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2540 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2544 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2545 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2546 MenuInfo
->FocusedItem
,
2547 (LPARAM
)MenuInfo
->Self
);
2549 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2553 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2559 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2566 /***********************************************************************
2569 * Return TRUE if we can go on with menu tracking.
2571 static BOOL FASTCALL
2572 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2575 ROSMENUINFO MenuInfo
;
2576 ROSMENUITEMINFO Item
;
2578 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2582 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2586 if (IS_SYSTEM_MENU(&MenuInfo
))
2592 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2594 MenuInitRosMenuItemInfo(&Item
);
2595 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2597 MenuCleanupRosMenuItemInfo(&Item
);
2601 if (!(Item
.fType
& MF_SEPARATOR
) &&
2602 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2604 if (MenuInfo
.FocusedItem
!= Index
)
2606 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2609 /* If the popup menu is not already "popped" */
2610 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2612 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2616 MenuCleanupRosMenuItemInfo(&Item
);
2621 /* else the click was on the menu bar, finish the tracking */
2626 /***********************************************************************
2629 * Return the value of MenuExecFocusedItem if
2630 * the selected item was not a popup. Else open the popup.
2631 * A -1 return value indicates that we go on with menu tracking.
2635 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2638 ROSMENUINFO MenuInfo
;
2639 ROSMENUITEMINFO ItemInfo
;
2641 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2646 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2651 if (! IS_SYSTEM_MENU(&MenuInfo
))
2653 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2655 MenuInitRosMenuItemInfo(&ItemInfo
);
2656 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2657 MenuInfo
.FocusedItem
== Id
)
2659 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2661 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2662 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2663 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2665 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2667 /* If we are dealing with the top-level menu */
2668 /* and this is a click on an already "popped" item: */
2669 /* Stop the menu tracking and close the opened submenus */
2670 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2672 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2676 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2677 MenuInfo
.TimeToHide
= TRUE
;
2678 MenuSetRosMenuInfo(&MenuInfo
);
2684 /***********************************************************************
2687 * Walks menu chain trying to find a menu pt maps to.
2689 static HMENU FASTCALL
2690 MenuPtMenu(HMENU Menu
, POINT Pt
)
2692 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2693 ROSMENUINFO MenuInfo
;
2694 ROSMENUITEMINFO ItemInfo
;
2698 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2703 /* try subpopup first (if any) */
2704 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2706 MenuInitRosMenuItemInfo(&ItemInfo
);
2707 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2708 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2709 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2711 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2714 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2718 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2721 /* check the current window (avoiding WM_HITTEST) */
2722 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2723 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2725 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2730 else if (HTSYSMENU
== Ht
)
2732 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2734 else if (HTMENU
== Ht
)
2736 Ret
= GetMenu(MenuInfo
.Wnd
);
2742 /***********************************************************************
2745 * Return TRUE if we can go on with menu tracking.
2747 static BOOL FASTCALL
2748 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2751 ROSMENUINFO MenuInfo
;
2752 ROSMENUITEMINFO ItemInfo
;
2756 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2760 if (IS_SYSTEM_MENU(&MenuInfo
))
2766 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2771 Index
= NO_SELECTED_ITEM
;
2774 if (NO_SELECTED_ITEM
== Index
)
2776 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2777 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2779 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2783 else if (MenuInfo
.FocusedItem
!= Index
)
2785 MenuInitRosMenuItemInfo(&ItemInfo
);
2786 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2787 !(ItemInfo
.fType
& MF_SEPARATOR
))
2789 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2790 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2791 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2793 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2799 /******************************************************************************
2801 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2803 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2806 PROSMENUITEMINFO MenuItems
;
2808 i
= MenuInfo
->FocusedItem
;
2809 if (NO_SELECTED_ITEM
== i
)
2814 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2816 return NO_SELECTED_ITEM
;
2819 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2821 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2827 return NO_SELECTED_ITEM
;
2830 /******************************************************************************
2832 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2834 static UINT FASTCALL
2835 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2838 PROSMENUITEMINFO MenuItems
;
2840 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2842 return NO_SELECTED_ITEM
;
2845 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2847 return NO_SELECTED_ITEM
;
2850 /* Find the start of the column */
2852 for (i
= MenuInfo
->FocusedItem
;
2853 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2861 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2862 return NO_SELECTED_ITEM
;
2865 for (--i
; 0 != i
; --i
)
2867 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2873 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2874 TRACE("ret %d.\n", i
);
2879 /***********************************************************************
2882 * Return the handle of the selected sub-popup menu (if any).
2884 static HMENU FASTCALL
2885 MenuGetSubPopup(HMENU Menu
)
2887 ROSMENUINFO MenuInfo
;
2888 ROSMENUITEMINFO ItemInfo
;
2890 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2891 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2896 MenuInitRosMenuItemInfo(&ItemInfo
);
2897 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2899 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2902 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2904 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2905 return ItemInfo
.hSubMenu
;
2908 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2912 /***********************************************************************
2915 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2917 static LRESULT FASTCALL
2918 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2920 ROSMENUINFO TopMenuInfo
;
2921 ROSMENUINFO MenuInfo
;
2923 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2925 return (LRESULT
) FALSE
;
2928 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2929 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2931 MDINEXTMENU NextMenu
;
2936 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2937 NextMenu
.hmenuNext
= NULL
;
2938 NextMenu
.hwndNext
= NULL
;
2939 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2941 TRACE("%p [%p] -> %p [%p]\n",
2942 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2944 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2946 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2947 NewWnd
= Mt
->OwnerWnd
;
2948 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2950 /* switch to the menu bar */
2952 if (0 != (Style
& WS_CHILD
)
2953 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2960 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2964 Id
= MenuInfo
.MenuItemCount
- 1;
2967 else if (0 != (Style
& WS_SYSMENU
))
2969 /* switch to the system menu */
2970 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2977 else /* application returned a new menu to switch to */
2979 NewMenu
= NextMenu
.hmenuNext
;
2980 NewWnd
= NextMenu
.hwndNext
;
2982 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2984 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2986 if (0 != (Style
& WS_SYSMENU
)
2987 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2989 /* get the real system menu */
2990 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2992 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2994 /* FIXME: Not sure what to do here;
2995 * perhaps try to track NewMenu as a popup? */
2997 WARN(" -- got confused.\n");
3007 if (NewMenu
!= Mt
->TopMenu
)
3009 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3011 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3013 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
3017 if (NewWnd
!= Mt
->OwnerWnd
)
3019 Mt
->OwnerWnd
= NewWnd
;
3020 SetCapture(Mt
->OwnerWnd
);
3021 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
3024 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3025 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3027 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3036 /***********************************************************************
3039 * The idea is not to show the popup if the next input message is
3040 * going to hide it anyway.
3042 static BOOL FASTCALL
3043 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
3047 Msg
.hwnd
= Mt
->OwnerWnd
;
3049 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3050 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
3055 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3056 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
3058 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3059 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3060 if (WM_KEYDOWN
== Msg
.message
3061 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
3063 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3070 /* failures go through this */
3071 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3076 /***********************************************************************
3079 * Handle a VK_ESCAPE key event in a menu.
3081 static BOOL FASTCALL
3082 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3084 BOOL EndMenu
= TRUE
;
3085 ROSMENUINFO MenuInfo
;
3086 HMENU MenuTmp
, MenuPrev
;
3088 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3090 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3091 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
3093 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3095 /* close topmost popup */
3096 while (MenuTmp
!= Mt
->CurrentMenu
)
3099 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3102 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3104 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
3106 Mt
->CurrentMenu
= MenuPrev
;
3114 /***********************************************************************
3117 * Handle a VK_LEFT key event in a menu.
3119 static void FASTCALL
3120 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3122 ROSMENUINFO MenuInfo
;
3123 ROSMENUINFO TopMenuInfo
;
3124 ROSMENUINFO PrevMenuInfo
;
3125 HMENU MenuTmp
, MenuPrev
;
3128 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3130 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3135 /* Try to move 1 column left (if possible) */
3136 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3138 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3140 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3145 /* close topmost popup */
3146 while (MenuTmp
!= Mt
->CurrentMenu
)
3149 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3152 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3156 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
3157 Mt
->CurrentMenu
= MenuPrev
;
3159 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3163 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3165 /* move menu bar selection if no more popups are left */
3167 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
3169 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3172 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3174 /* A sublevel menu was displayed - display the next one
3175 * unless there is another displacement coming up */
3177 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3178 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3180 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3187 /***********************************************************************
3190 * Handle a VK_RIGHT key event in a menu.
3192 static void FASTCALL
3193 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3196 ROSMENUINFO MenuInfo
;
3197 ROSMENUINFO CurrentMenuInfo
;
3200 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3201 Mt
->CurrentMenu
, Mt
->TopMenu
);
3203 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3207 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3209 /* If already displaying a popup, try to display sub-popup */
3211 MenuTmp
= Mt
->CurrentMenu
;
3212 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3214 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3217 /* if subpopup was displayed then we are done */
3218 if (MenuTmp
!= Mt
->CurrentMenu
)
3224 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3229 /* Check to see if there's another column */
3230 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3232 TRACE("Going to %d.\n", NextCol
);
3233 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3235 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3240 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3242 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3244 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3245 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3252 /* try to move to the next item */
3253 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
3255 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3258 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3260 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3261 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3263 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3270 /***********************************************************************
3273 * Find the menu item selected by a key press.
3274 * Return item id, -1 if none, -2 if we should close the menu.
3276 static UINT FASTCALL
3277 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
3278 WCHAR Key
, BOOL ForceMenuChar
)
3280 ROSMENUINFO SysMenuInfo
;
3281 PROSMENUITEMINFO Items
, ItemInfo
;
3285 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
3287 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
3289 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
3291 MenuInfo
= &SysMenuInfo
;
3299 if (NULL
!= MenuInfo
)
3301 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
3305 if (! ForceMenuChar
)
3307 Key
= toupperW(Key
);
3309 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
3311 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
3313 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
3316 p
= strchrW(p
+ 2, '&');
3318 while (NULL
!= p
&& L
'&' == p
[1]);
3319 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
3327 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
3328 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
3329 if (2 == HIWORD(MenuChar
))
3331 return LOWORD(MenuChar
);
3333 if (1 == HIWORD(MenuChar
))
3342 /***********************************************************************
3345 * Menu tracking code.
3348 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3349 HWND Wnd
, const RECT
*Rect
)
3352 ROSMENUINFO MenuInfo
;
3353 ROSMENUITEMINFO ItemInfo
;
3355 INT ExecutedMenuId
= -1;
3357 BOOL EnterIdleSent
= FALSE
;
3360 Mt
.CurrentMenu
= Menu
;
3366 TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3367 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3368 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3372 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3377 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3382 if (0 != (Flags
& TPM_BUTTONDOWN
))
3384 /* Get the result in order to start the tracking or not */
3385 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3386 fEndMenu
= ! fRemove
;
3389 SetCapture(Mt
.OwnerWnd
);
3390 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
.OwnerWnd
);
3394 /* we have to keep the message in the queue until it's
3395 * clear that menu loop is not over yet. */
3399 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3401 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3405 /* remove the message from the queue */
3406 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3410 if (! EnterIdleSent
)
3412 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3413 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3414 EnterIdleSent
= TRUE
;
3415 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3421 /* check if EndMenu() tried to cancel us, by posting this message */
3422 if (WM_CANCELMODE
== Msg
.message
)
3424 /* we are now out of the loop */
3427 /* remove the message from the queue */
3428 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3430 /* break out of internal loop, ala ESCAPE */
3434 TranslateMessage(&Msg
);
3437 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3439 EnterIdleSent
= FALSE
;
3443 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3446 * Use the mouse coordinates in lParam instead of those in the MSG
3447 * struct to properly handle synthetic messages. They are already
3448 * in screen coordinates.
3450 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3451 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3453 /* Find a menu for this mouse event */
3454 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3458 /* no WM_NC... messages in captured state */
3460 case WM_RBUTTONDBLCLK
:
3461 case WM_RBUTTONDOWN
:
3462 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3467 case WM_LBUTTONDBLCLK
:
3468 case WM_LBUTTONDOWN
:
3469 /* If the message belongs to the menu, removes it from the queue */
3470 /* Else, end menu tracking */
3471 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3472 fEndMenu
= ! fRemove
;
3476 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3482 /* Check if a menu was selected by the mouse */
3485 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3487 /* End the loop if ExecutedMenuId is an item ID */
3488 /* or if the job was done (ExecutedMenuId = 0). */
3489 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3493 /* No menu was selected by the mouse */
3494 /* if the function was called by TrackPopupMenu, continue
3495 with the menu tracking. If not, stop it */
3496 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3503 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3507 } /* switch(Msg.message) - mouse */
3509 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3511 fRemove
= TRUE
; /* Keyboard messages are always removed */
3523 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3525 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3527 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3528 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3533 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3534 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3536 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3538 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3540 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3544 else /* otherwise try to move selection */
3546 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3552 MenuKeyLeft(&Mt
, Flags
);
3556 MenuKeyRight(&Mt
, Flags
);
3560 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3566 hi
.cbSize
= sizeof(HELPINFO
);
3567 hi
.iContextType
= HELPINFO_MENUITEM
;
3568 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3570 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3576 MenuInitRosMenuItemInfo(&ItemInfo
);
3577 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3578 MenuInfo
.FocusedItem
,
3581 hi
.iCtrlId
= ItemInfo
.wID
;
3587 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3590 hi
.hItemHandle
= Menu
;
3591 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3592 hi
.MousePos
= Msg
.pt
;
3593 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3600 break; /* WM_KEYDOWN */
3607 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3611 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3613 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3614 fEndMenu
= (ExecutedMenuId
!= -2);
3618 /* Hack to avoid control chars. */
3619 /* We will find a better way real soon... */
3620 if (Msg
.wParam
< 32)
3625 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3626 LOWORD(Msg
.wParam
), FALSE
);
3627 if ((UINT
) -2 == Pos
)
3631 else if ((UINT
) -1 == Pos
)
3637 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3638 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3639 fEndMenu
= (-2 != ExecutedMenuId
);
3643 } /* switch(msg.message) - kbd */
3647 PeekMessageW( &Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3648 DispatchMessageW(&Msg
);
3657 /* finally remove message from the queue */
3659 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3661 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3665 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3669 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3670 SetCapture(NULL
); /* release the capture */
3672 /* If dropdown is still painted and the close box is clicked on
3673 then the menu will be destroyed as part of the DispatchMessage above.
3674 This will then invalidate the menu handle in Mt.hTopMenu. We should
3675 check for this first. */
3676 if (IsMenu(Mt
.TopMenu
))
3678 if (IsWindow(Mt
.OwnerWnd
))
3680 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3682 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3684 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3686 DestroyWindow(MenuInfo
.Wnd
);
3687 MenuInfo
.Wnd
= NULL
;
3689 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3690 SendMessageW( Mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)Mt
.TopMenu
,
3691 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3694 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3697 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3700 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3702 /* Reset the variable for hiding menu */
3703 MenuInfo
.TimeToHide
= FALSE
;
3704 MenuSetRosMenuInfo(&MenuInfo
);
3708 /* The return value is only used by TrackPopupMenu */
3709 if (!(Flags
& TPM_RETURNCMD
)) return TRUE
;
3710 if (ExecutedMenuId
< 0) ExecutedMenuId
= 0;
3711 return ExecutedMenuId
;
3714 /***********************************************************************
3717 static BOOL FASTCALL
3718 MenuExitTracking(HWND Wnd
)
3720 TRACE("hwnd=%p\n", Wnd
);
3722 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3729 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3731 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3732 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3734 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, Pt
.x
, Pt
.y
);
3738 /* map point to parent client coordinates */
3739 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3740 if (Parent
!= GetDesktopWindow())
3742 ScreenToClient(Parent
, &Pt
);
3745 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3746 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3747 MenuExitTracking(Wnd
);
3753 MenuTrackKbdMenuBar(HWND hWnd
, UINT wParam
, WCHAR wChar
)
3755 UINT uItem
= NO_SELECTED_ITEM
;
3757 ROSMENUINFO MenuInfo
;
3758 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3760 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd
, wParam
, wChar
);
3762 /* find window that has a menu */
3764 while (!((GetWindowLongPtrW( hWnd
, GWL_STYLE
) &
3765 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3766 if (!(hWnd
= GetAncestor( hWnd
, GA_PARENT
))) return;
3768 /* check if we have to track a system menu */
3770 hTrackMenu
= GetMenu( hWnd
);
3771 if (!hTrackMenu
|| IsIconic(hWnd
) || wChar
== ' ' )
3773 if (!(GetWindowLongPtrW( hWnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3774 hTrackMenu
= NtUserGetSystemMenu(hWnd
, FALSE
);
3776 wParam
|= HTSYSMENU
; /* prevent item lookup */
3779 if (!IsMenu( hTrackMenu
)) return;
3781 MenuInitTracking( hWnd
, hTrackMenu
, FALSE
, wFlags
);
3783 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3788 if( wChar
&& wChar
!= ' ' )
3790 uItem
= MenuFindItemByKey( hWnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3791 if ( uItem
>= (UINT
)(-2) )
3793 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3794 /* schedule end of menu tracking */
3795 wFlags
|= TF_ENDMENU
;
3800 MenuSelectItem( hWnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3802 if (wParam
& HTSYSMENU
)
3804 /* prevent sysmenu activation for managed windows on Alt down/up */
3805 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3806 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3810 if( uItem
== NO_SELECTED_ITEM
)
3811 MenuMoveSelection( hWnd
, &MenuInfo
, ITEM_NEXT
);
3813 PostMessageW( hWnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3817 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hWnd
, NULL
);
3818 MenuExitTracking( hWnd
);
3824 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3825 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3827 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3829 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3830 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3831 * MFT_STRING is replaced by MIIM_STRING.
3832 * (So, I guess we should use MIIM_STRING only for strings?)
3834 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3836 * Based on wine, SetMenuItemInfo_common:
3837 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3838 * it will result in a error.
3839 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3840 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3847 LPMENUITEMINFOW mii
,
3854 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3856 if(Flags
& MF_BITMAP
)
3858 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3859 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3861 if (Flags
& MF_HELP
)
3863 /* increase ident */
3864 mii
->fType
|= MF_HELP
;
3867 else if(Flags
& MF_OWNERDRAW
)
3869 mii
->fType
|= MFT_OWNERDRAW
;
3870 mii
->fMask
|= MIIM_DATA
;
3871 mii
->dwItemData
= (DWORD
) NewItem
;
3873 else if (Flags
& MF_SEPARATOR
)
3875 mii
->fType
|= MFT_SEPARATOR
;
3876 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3877 Flags
|= MF_GRAYED
|MF_DISABLED
;
3879 else /* Default action MF_STRING. */
3881 /* Item beginning with a backspace is a help item */
3882 if (NewItem
!= NULL
)
3886 if (*NewItem
== '\b')
3888 mii
->fType
|= MF_HELP
;
3894 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3895 if (*NewItemA
== '\b')
3897 mii
->fType
|= MF_HELP
;
3899 NewItem
= (LPCWSTR
) NewItemA
;
3903 if (Flags
& MF_HELP
)
3904 mii
->fType
|= MF_HELP
;
3905 mii
->fMask
|= MIIM_STRING
;
3906 mii
->fType
|= MFT_STRING
; /* Zero */
3907 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3909 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3911 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3915 mii
->fType
|= MFT_SEPARATOR
;
3916 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3917 Flags
|= MF_GRAYED
|MF_DISABLED
;
3921 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3923 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3926 if(Flags
& MF_MENUBREAK
)
3928 mii
->fType
|= MFT_MENUBREAK
;
3930 else if(Flags
& MF_MENUBARBREAK
)
3932 mii
->fType
|= MFT_MENUBARBREAK
;
3935 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3937 if (Flags
& MF_GRAYED
)
3938 mii
->fState
|= MF_GRAYED
;
3940 if (Flags
& MF_DISABLED
)
3941 mii
->fState
|= MF_DISABLED
;
3943 mii
->fMask
|= MIIM_STATE
;
3945 else if (Flags
& MF_HILITE
)
3947 mii
->fState
|= MF_HILITE
;
3948 mii
->fMask
|= MIIM_STATE
;
3950 else /* default state */
3952 mii
->fState
|= MFS_ENABLED
;
3953 mii
->fMask
|= MIIM_STATE
;
3956 if(Flags
& MF_POPUP
)
3958 mii
->fType
|= MF_POPUP
;
3959 mii
->fMask
|= MIIM_SUBMENU
;
3960 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3964 mii
->fMask
|= MIIM_ID
;
3965 mii
->wID
= (UINT
)IDNewItem
;
3971 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3973 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3976 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3978 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3979 IS_INTRESOURCE(Common
->MenuName
) ?
3980 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3981 (LPCWSTR
)&Common
->MenuName
);
3983 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3987 /* FUNCTIONS *****************************************************************/
3990 MenuIsStringItem(ULONG TypeData)
3992 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
4000 AppendMenuA(HMENU hMenu
,
4002 UINT_PTR uIDNewItem
,
4005 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
4014 AppendMenuW(HMENU hMenu
,
4016 UINT_PTR uIDNewItem
,
4019 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
4028 CheckMenuItem(HMENU hmenu
,
4032 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4037 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
4040 PROSMENUITEMINFO Items
= NULL
;
4041 UINT cChecked
, cUnchecked
;
4045 if(idFirst
> idLast
)
4048 ItemCount
= GetMenuItemCount(hMenu
);
4050 //mi.cbSize = sizeof(ROSMENUINFO);
4051 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
4054 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
4056 ERR("MenuGetAllRosMenuItemInfo failed\n");
4060 cChecked
= cUnchecked
= 0;
4062 for (i
= 0 ; i
< ItemCount
; i
++)
4065 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
4066 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
4068 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
4070 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
4073 if (uFlags
& MF_BYPOSITION
)
4075 if (i
< idFirst
|| i
> idLast
)
4090 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
4093 if (Items
[i
].wID
== idCheck
)
4107 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4110 Items
[i
].fType
|= MFT_RADIOCHECK
;
4111 Items
[i
].fState
|= MFS_CHECKED
;
4115 Items
[i
].fState
&= ~MFS_CHECKED
;
4118 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4120 ERR("MenuSetRosMenuItemInfo failed\n");
4125 HeapFree(GetProcessHeap(), 0, Items
);
4127 *pChecked
+= cChecked
;
4128 *pUnchecked
+= cUnchecked
;
4130 if (cChecked
|| cUnchecked
)
4140 CheckMenuRadioItem(HMENU hmenu
,
4147 UINT cUnchecked
= 0;
4148 UINT cMenuChanged
= 0;
4150 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4153 if (cMenuChanged
> 1)
4160 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4163 return (cChecked
!= 0);
4174 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4182 CreatePopupMenu(VOID
)
4185 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4193 DrawMenuBar(HWND hWnd
)
4195 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4196 ROSMENUINFO MenuInfo
;
4198 hMenu
= GetMenu(hWnd
);
4201 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4202 MenuInfo
.Height
= 0; // make sure to recalc size
4203 MenuSetRosMenuInfo(&MenuInfo
);
4204 /* The wine method doesn't work and I suspect it's more effort
4205 then hackfix solution
4206 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4207 SWP_NOZORDER | SWP_FRAMECHANGED );
4210 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4219 EnableMenuItem(HMENU hMenu
,
4223 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4233 guii
.cbSize
= sizeof(GUITHREADINFO
);
4234 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4236 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4248 PWND Wnd
= ValidateHwnd(hWnd
);
4253 return (HMENU
)Wnd
->IDMenu
;
4261 GetMenuCheckMarkDimensions(VOID
)
4263 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4264 GetSystemMetrics(SM_CYMENUCHECK
)));
4272 GetMenuDefaultItem(HMENU hMenu
,
4276 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4284 GetMenuInfo(HMENU hmenu
,
4290 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4293 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4294 mi
.cbSize
= sizeof(MENUINFO
);
4295 mi
.fMask
= lpcmi
->fMask
;
4297 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4299 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4308 GetMenuItemCount(HMENU Menu
)
4310 ROSMENUINFO MenuInfo
;
4312 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4320 GetMenuItemID(HMENU hMenu
,
4323 ROSMENUITEMINFO mii
;
4325 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4326 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4328 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4333 if (NULL
!= mii
.hSubMenu
)
4354 LPMENUITEMINFOA mii
)
4360 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4361 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4363 SetLastError(ERROR_INVALID_PARAMETER
);
4367 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4369 /* No text requested, just pass on */
4370 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4373 AnsiBuffer
= mii
->dwTypeData
;
4374 Count
= miiW
.cch
= mii
->cch
;
4375 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4376 miiW
.dwTypeData
= 0;
4380 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4381 miiW
.cch
* sizeof(WCHAR
));
4382 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4383 miiW
.dwTypeData
[0] = 0;
4386 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4388 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4392 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4394 if (!AnsiBuffer
|| !Count
)
4396 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4397 mii
->dwTypeData
= AnsiBuffer
;
4398 mii
->cch
= miiW
.cch
;
4402 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4406 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4410 if (Count
> miiW
.cch
)
4412 AnsiBuffer
[miiW
.cch
] = 0;
4414 mii
->cch
= mii
->cch
;
4422 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4423 mii
->dwTypeData
= AnsiBuffer
;
4437 LPMENUITEMINFOW mii
)
4443 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4444 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4446 SetLastError(ERROR_INVALID_PARAMETER
);
4450 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4452 /* No text requested, just pass on */
4453 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4456 String
= mii
->dwTypeData
;
4458 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4459 miiW
.dwTypeData
= 0;
4463 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4464 miiW
.cch
* sizeof(WCHAR
));
4465 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4466 miiW
.dwTypeData
[0] = 0;
4469 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4471 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4475 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4477 if (!String
|| !Count
)
4479 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4480 mii
->dwTypeData
= String
; // may not be zero.
4481 mii
->cch
= miiW
.cch
;
4485 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4487 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4490 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4491 mii
->dwTypeData
= String
;
4492 mii
->cch
= strlenW(String
);
4507 ROSMENUINFO MenuInfo
;
4508 ROSMENUITEMINFO mii
;
4509 memset( &mii
, 0, sizeof(mii
) );
4510 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4511 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4514 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4519 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4523 nSubItems
= MenuInfo
.MenuItemCount
;
4525 /* FIXME - ported from wine, does that work (0xff)? */
4526 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4527 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4529 return (UINT
)-1; /* Invalid submenu */
4532 /* FIXME - ported from wine, does that work? */
4533 return (mii
.fType
| mii
.fState
);
4553 memset( &mii
, 0, sizeof(mii
) );
4554 mii
.dwTypeData
= lpString
;
4555 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4556 mii
.fType
= MFT_STRING
;
4557 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4558 mii
.cch
= nMaxCount
;
4560 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4580 memset( &miiW
, 0, sizeof(miiW
) );
4581 miiW
.dwTypeData
= lpString
;
4582 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4583 miiW
.fType
= MFT_STRING
;
4584 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4585 miiW
.cch
= nMaxCount
;
4587 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4605 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4606 mi
.fMask
= MIIM_SUBMENU
;
4608 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4610 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4627 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4629 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4642 UINT_PTR uIDNewItem
,
4646 memset( &mii
, 0, sizeof(mii
) );
4647 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4648 mii
.fMask
= MIIM_FTYPE
;
4650 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4653 (LPCWSTR
) lpNewItem
,
4656 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4670 LPCMENUITEMINFOA lpmii
)
4673 UNICODE_STRING MenuText
;
4675 BOOL CleanHeap
= FALSE
;
4678 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4679 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4681 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4683 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4685 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4688 /* copy the text string */
4689 if (((mi
.fMask
& MIIM_STRING
) ||
4690 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4691 && mi
.dwTypeData
!= NULL
)
4693 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4694 if (!NT_SUCCESS (Status
))
4696 SetLastError (RtlNtStatusToDosError(Status
));
4699 mi
.dwTypeData
= MenuText
.Buffer
;
4700 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4703 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4705 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4720 LPCMENUITEMINFOW lpmii
)
4723 UNICODE_STRING MenuText
;
4726 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4727 if a bad user passes bad data, we crash his process instead of the
4730 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4731 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4733 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4735 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4737 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4740 /* copy the text string */
4741 if (((mi
.fMask
& MIIM_STRING
) ||
4742 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4743 && mi
.dwTypeData
!= NULL
)
4745 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4746 mi
.dwTypeData
= MenuText
.Buffer
;
4747 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4749 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4764 UINT_PTR uIDNewItem
,
4768 memset( &mii
, 0, sizeof(mii
) );
4769 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4770 mii
.fMask
= MIIM_FTYPE
;
4772 MenuSetItemData( &mii
,
4778 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4790 ROSMENUINFO MenuInfo
;
4792 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4800 LoadMenuA(HINSTANCE hInstance
,
4803 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4804 if (Resource
== NULL
)
4808 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4816 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4818 return(LoadMenuIndirectW(lpMenuTemplate
));
4826 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4829 WORD version
, offset
;
4830 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4832 version
= GET_WORD(p
);
4837 case 0: /* standard format is version of 0 */
4838 offset
= GET_WORD(p
);
4839 p
+= sizeof(WORD
) + offset
;
4840 if (!(hMenu
= CreateMenu())) return 0;
4841 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4847 case 1: /* extended format is version of 1 */
4848 offset
= GET_WORD(p
);
4849 p
+= sizeof(WORD
) + offset
;
4850 if (!(hMenu
= CreateMenu())) return 0;
4851 if (!MENUEX_ParseResource(p
, hMenu
))
4853 DestroyMenu( hMenu
);
4858 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4868 LoadMenuW(HINSTANCE hInstance
,
4871 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4872 if (Resource
== NULL
)
4876 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4890 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4903 UINT_PTR uIDNewItem
,
4907 ROSMENUITEMINFO rmii
;
4909 memset( &mii
, 0, sizeof(mii
) );
4910 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4911 mii
.fMask
= MIIM_FTYPE
;
4913 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4917 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4919 MenuInitRosMenuItemInfo( &rmii
);
4921 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4923 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4924 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4926 MenuCleanupRosMenuItemInfo( &rmii
);
4928 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4931 (LPCWSTR
) lpNewItem
,
4934 return SetMenuItemInfoA( hMnu
,
4936 (BOOL
)(MF_BYPOSITION
& uFlags
),
4950 UINT_PTR uIDNewItem
,
4954 ROSMENUITEMINFO rmii
;
4956 memset ( &mii
, 0, sizeof(mii
) );
4957 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4958 mii
.fMask
= MIIM_FTYPE
;
4960 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4962 mi
.Height
= 0; // Force size recalculation.
4964 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4966 MenuInitRosMenuItemInfo( &rmii
);
4968 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4970 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4971 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4973 MenuCleanupRosMenuItemInfo( &rmii
);
4975 /* Init new data for this menu item */
4976 MenuSetItemData( &mii
,
4982 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4983 return SetMenuItemInfoW( hMnu
,
4985 (BOOL
)(MF_BYPOSITION
& uFlags
),
4997 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
5013 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
5015 SetLastError(ERROR_INVALID_PARAMETER
);
5019 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5020 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
5033 HBITMAP hBitmapUnchecked
,
5034 HBITMAP hBitmapChecked
)
5036 ROSMENUITEMINFO uItem
;
5037 memset ( &uItem
, 0, sizeof(uItem
) );
5038 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
5040 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
5041 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
5043 if (!hBitmapChecked
&& !hBitmapUnchecked
)
5045 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
5047 else /* Install new bitmaps */
5049 uItem
.hbmpChecked
= hBitmapChecked
;
5050 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5051 uItem
.fState
|= MF_USECHECKBITMAPS
;
5053 return NtUserMenuItemInfo(hMenu
, uPosition
,
5054 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
5067 LPCMENUITEMINFOA lpmii
)
5069 MENUITEMINFOW MenuItemInfoW
;
5070 UNICODE_STRING UnicodeString
;
5072 ULONG Result
= FALSE
;
5074 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5076 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5078 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5079 MenuItemInfoW
.hbmpItem
= NULL
;
5082 * MIIM_STRING == good
5083 * MIIM_TYPE & MFT_STRING == good
5084 * MIIM_STRING & MFT_STRING == good
5085 * MIIM_STRING & MFT_OWNERSRAW == good
5087 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5088 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5089 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5090 && MenuItemInfoW
.dwTypeData
!= NULL
)
5092 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5093 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5094 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5095 if (!NT_SUCCESS (Status
))
5097 SetLastError (RtlNtStatusToDosError(Status
));
5100 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5101 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5105 UnicodeString
.Buffer
= NULL
;
5108 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5109 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5111 if (UnicodeString
.Buffer
!= NULL
)
5113 RtlFreeUnicodeString(&UnicodeString
);
5129 LPCMENUITEMINFOW lpmii
)
5131 MENUITEMINFOW MenuItemInfoW
;
5134 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5136 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5138 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5139 MenuItemInfoW
.hbmpItem
= NULL
;
5142 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5143 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5144 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5145 && MenuItemInfoW
.dwTypeData
!= NULL
)
5147 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5149 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5150 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5166 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5171 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5174 return NtUserSetSystemMenu(hwnd
, hMenu
);
5196 SetLastError( ERROR_INVALID_MENU_HANDLE
);
5200 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
5202 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
5203 if (0 == (Flags
& TPM_NONOTIFY
))
5205 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5208 if (MenuShowPopup(Wnd
, Menu
, 0, x
, y
, 0, 0 ))
5210 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5212 MenuExitTracking(Wnd
);
5231 /* Not fully implemented */
5232 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5233 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5237 // Example for the Win32/User32 rewrite.
5238 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5252 return NtUserTrackPopupMenuEx( Menu
,
5257 NULL
); // LPTPMPARAMS is null
5266 GetMenuContextHelpId(HMENU hmenu
)
5269 mi
.cbSize
= sizeof(ROSMENUINFO
);
5270 mi
.fMask
= MIM_HELPID
;
5272 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5274 return mi
.dwContextHelpID
;
5295 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5298 Result
= (ULONG_PTR
)lResult
;
5303 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5323 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5326 Result
= (ULONG_PTR
)lResult
;
5331 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5342 LPCWSTR lpszNewItem
,
5347 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5348 for MF_DELETE. We should check the parameters for all others
5349 MF_* actions also (anybody got a doc on ChangeMenu?).
5352 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5355 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5358 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5361 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5364 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5365 flags
&~ MF_REMOVE
);
5367 default : /* MF_INSERT */
5368 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5385 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5386 for MF_DELETE. We should check the parameters for all others
5387 MF_* actions also (anybody got a doc on ChangeMenu?).
5390 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5393 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5396 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5399 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5402 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5403 flags
&~ MF_REMOVE
);
5405 default : /* MF_INSERT */
5406 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);