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 /* internal popup menu window messages */
20 #define MM_SETMENUHANDLE (WM_USER + 0)
21 #define MM_GETMENUHANDLE (WM_USER + 1)
23 /* Internal MenuTrackMenu() flags */
24 #define TPM_INTERNAL 0xF0000000
25 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
26 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
27 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
29 /* TYPES *********************************************************************/
31 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
33 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
34 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
35 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
37 #define IS_SYSTEM_MENU(MenuInfo) \
38 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
40 #define IS_SYSTEM_POPUP(MenuInfo) \
41 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
43 #define IS_MAGIC_ITEM(Bmp) ((int) Bmp <12)
44 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
46 #define MENU_ITEM_HBMP_SPACE (5)
47 #define MENU_BAR_ITEMS_SPACE (12)
48 #define SEPARATOR_HEIGHT (5)
49 #define MENU_TAB_SPACE (8)
54 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
55 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
56 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
57 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
59 /* internal flags for menu tracking */
61 #define TF_ENDMENU 0x0001
62 #define TF_SUSPENDPOPUP 0x0002
63 #define TF_SKIPREMOVE 0x0004
68 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
69 HMENU TopMenu
; /* initial menu */
70 HWND OwnerWnd
; /* where notifications are sent */
74 static LRESULT WINAPI
PopupMenuWndProcW(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
76 /*********************************************************************
77 * PopupMenu class descriptor
79 const struct builtin_class_descr POPUPMENU_builtin_class
=
81 POPUPMENU_CLASS_ATOMW
, /* name */
82 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
83 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
84 (WNDPROC
) NULL
, /* FIXME - procA */
85 sizeof(MENUINFO
*), /* extra */
86 (LPCWSTR
) IDC_ARROW
, /* cursor */
87 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
91 /* INTERNAL FUNCTIONS ********************************************************/
93 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
94 * Of course I didnt copy the ASM code because we want this to be portable
95 * and it needs to go away.
99 #define GET_WORD(ptr) (*(WORD *)(ptr))
102 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
105 HFONT hMenuFont
= NULL
;
106 HFONT hMenuFontBold
= NULL
;
108 /* Flag set by EndMenu() to force an exit from menu tracking */
109 static BOOL fEndMenu
= FALSE
;
111 /* Use global popup window because there's no way 2 menus can
112 * be tracked at the same time. */
113 static HWND TopPopup
;
115 /* Dimension of the menu bitmaps */
116 static WORD ArrowBitmapWidth
= 0, ArrowBitmapHeight
= 0;
118 static HBITMAP StdMnArrow
= NULL
;
119 static HBITMAP BmpSysMenu
= NULL
;
121 static SIZE MenuCharSize
;
123 /***********************************************************************
126 * Get full information about menu
129 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
131 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
132 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
134 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
137 /***********************************************************************
140 * Set full information about menu
143 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
145 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
146 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
148 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
151 /***********************************************************************
152 * MenuInitRosMenuItemInfo
154 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
157 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
159 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
160 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
163 /***********************************************************************
164 * MenuGetRosMenuItemInfo
166 * Get full information about a menu item
169 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
171 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
173 if (ItemInfo
->dwTypeData
!= NULL
)
175 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
179 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
180 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
181 ItemInfo
->dwTypeData
= NULL
;
183 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
189 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
192 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
193 ItemInfo
->cch
* sizeof(WCHAR
));
194 if (NULL
== ItemInfo
->dwTypeData
)
199 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
204 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
206 ItemInfo
->fMask
= Save_Mask
;
210 /***********************************************************************
211 * MenuSetRosMenuItemInfo
213 * Set selected information about a menu item, need to set the mask bits.
216 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
220 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
221 ItemInfo
->dwTypeData
!= NULL
)
223 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
225 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
230 /***********************************************************************
231 * MenuCleanupRosMenuItemInfo
233 * Cleanup after use of MenuGet/SetRosMenuItemInfo
236 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
238 if (ItemInfo
->dwTypeData
!= NULL
)
240 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
241 ItemInfo
->dwTypeData
= NULL
;
245 /***********************************************************************
246 * MenuGetAllRosMenuItemInfo
248 * Get full information about all menu items
251 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
255 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
256 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
260 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
261 if (NULL
== *ItemInfo
)
266 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
269 /***********************************************************************
270 * MenuCleanupAllRosMenuItemInfo
272 * Cleanup after use of MenuGetAllRosMenuItemInfo
275 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
277 HeapFree(GetProcessHeap(), 0, ItemInfo
);
281 /***********************************************************************
284 * Load the arrow bitmap. We can't do this from MenuInit since user32
285 * can also be used (and thus initialized) from text-mode.
288 MenuLoadBitmaps(VOID
)
290 /* Load menu bitmaps */
291 if (NULL
== StdMnArrow
)
293 StdMnArrow
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
295 if (NULL
!= StdMnArrow
)
298 GetObjectW(StdMnArrow
, sizeof(BITMAP
), &bm
);
299 ArrowBitmapWidth
= bm
.bmWidth
;
300 ArrowBitmapHeight
= bm
.bmHeight
;
304 /* Load system buttons bitmaps */
305 if (NULL
== BmpSysMenu
)
307 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
311 /***********************************************************************
312 * MenuGetBitmapItemSize
314 * Get the size of a bitmap item.
317 MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*Size
, HWND WndOwner
)
320 HBITMAP Bmp
= lpitem
->hbmpItem
;
322 Size
->cx
= Size
->cy
= 0;
324 /* check if there is a magic menu item associated with this item */
325 if (0 != Bmp
&& IS_MAGIC_ITEM((INT
)(Bmp
)))
327 switch((INT_PTR
) Bmp
)
329 case (INT_PTR
)HBMMENU_CALLBACK
:
331 MEASUREITEMSTRUCT measItem
;
332 measItem
.CtlType
= ODT_MENU
;
334 measItem
.itemID
= lpitem
->wID
;
335 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
336 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
337 measItem
.itemData
= lpitem
->dwItemData
;
338 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
339 Size
->cx
= measItem
.itemWidth
;
340 Size
->cy
= measItem
.itemHeight
;
345 case (INT_PTR
) HBMMENU_SYSTEM
:
346 if (0 != lpitem
->dwItemData
)
348 Bmp
= (HBITMAP
) lpitem
->dwItemData
;
352 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
353 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
354 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
355 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
356 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
357 /* FIXME: Why we need to subtract these magic values? */
358 /* to make them smaller than the menu bar? */
359 Size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
360 Size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
362 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
363 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
364 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
365 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
367 FIXME("Magic menu bitmap not implemented\n");
372 if (GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
374 Size
->cx
= Bm
.bmWidth
;
375 Size
->cy
= Bm
.bmHeight
;
379 /***********************************************************************
382 * Draw a bitmap item.
385 MenuDrawBitmapItem(HDC Dc
, PROSMENUITEMINFO Item
, const RECT
*Rect
,
386 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
392 int w
= Rect
->right
- Rect
->left
;
393 int h
= Rect
->bottom
- Rect
->top
;
396 HBITMAP hbmpToDraw
= (HBITMAP
) Item
->hbmpItem
;
399 /* Check if there is a magic menu item associated with this item */
400 if (IS_MAGIC_ITEM(hbmpToDraw
))
406 switch ((INT_PTR
)hbmpToDraw
)
408 case (INT_PTR
) HBMMENU_SYSTEM
:
409 if (NULL
!= Item
->dwTypeData
)
411 Bmp
= (HBITMAP
)Item
->dwTypeData
;
412 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
419 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
421 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
425 /* only use right half of the bitmap */
426 BmpXoffset
= Bm
.bmWidth
/ 2;
427 Bm
.bmWidth
-= BmpXoffset
;
430 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
431 Flags
= DFCS_CAPTIONRESTORE
;
433 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
435 Flags
= DFCS_CAPTIONMIN
;
437 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
439 Flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
441 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
442 Flags
= DFCS_CAPTIONCLOSE
;
444 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
445 Flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
447 case (INT_PTR
) HBMMENU_CALLBACK
:
449 DRAWITEMSTRUCT drawItem
;
451 drawItem
.CtlType
= ODT_MENU
;
453 drawItem
.itemID
= Item
->wID
;
454 drawItem
.itemAction
= odaction
;
455 drawItem
.itemState
= (Item
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
456 drawItem
.itemState
|= (Item
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
457 drawItem
.itemState
|= (Item
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
458 drawItem
.itemState
|= (Item
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
459 drawItem
.itemState
|= (Item
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
460 drawItem
.hwndItem
= (HWND
)hmenu
;
462 drawItem
.rcItem
= *Rect
;
463 drawItem
.itemData
= Item
->dwItemData
;
464 /* some applications make this assumption on the DC's origin */
465 SetViewportOrgEx( Dc
, Item
->Rect
.left
, Item
->Rect
.top
, &origorg
);
466 OffsetRect( &drawItem
.rcItem
, - Item
->Rect
.left
, - Item
->Rect
.top
);
467 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
468 SetViewportOrgEx( Dc
, origorg
.x
, origorg
.y
, NULL
);
473 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
474 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
475 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
476 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
478 FIXME("Magic menu bitmap not implemented\n");
481 InflateRect(&r
, -1, -1);
482 if (0 != (Item
->fState
& MF_HILITE
))
484 Flags
|= DFCS_PUSHED
;
486 DrawFrameControl(Dc
, &r
, DFC_CAPTION
, Flags
);
490 if (NULL
== Bmp
|| ! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
496 DcMem
= CreateCompatibleDC(Dc
);
497 SelectObject(DcMem
, Bmp
);
499 /* handle fontsize > bitmap_height */
500 Top
= (Bm
.bmHeight
< h
) ? Rect
->top
+ (h
- Bm
.bmHeight
) / 2 : Rect
->top
;
502 Rop
= ((Item
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmpToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
503 if ((Item
->fState
& MF_HILITE
) && Item
->hbmpItem
)
505 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
507 BitBlt(Dc
, Left
, Top
, w
, h
, DcMem
, BmpXoffset
, 0, Rop
);
511 /***********************************************************************
514 * Draw a single menu item.
517 MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC Dc
,
518 PROSMENUITEMINFO Item
, UINT Height
, BOOL MenuBar
, UINT Action
)
522 BOOL flat_menu
= FALSE
;
524 PWINDOW Wnd
= ValidateHwnd(hWnd
);
529 if (0 != (Item
->fType
& MF_SYSMENU
))
531 if ( (Wnd
->Style
& WS_MINIMIZE
))
533 UserGetInsideRectNC(Wnd
, &Rect
);
534 UserDrawSysMenuButton(hWnd
, Dc
, &Rect
,
535 Item
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
540 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
541 bkgnd
= (MenuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
545 if (0 != (Item
->fState
& MF_HILITE
))
547 if (MenuBar
&& !flat_menu
)
549 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
550 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
554 if (0 != (Item
->fState
& MF_GRAYED
))
556 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
560 SetTextColor(Dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
562 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
567 if (0 != (Item
->fState
& MF_GRAYED
))
569 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
573 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
575 SetBkColor(Dc
, GetSysColor(bkgnd
));
580 if (Item
->fType
& MF_OWNERDRAW
)
583 ** Experimentation under Windows reveals that an owner-drawn
584 ** menu is given the rectangle which includes the space it requested
585 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
586 ** and a popup-menu arrow. This is the value of lpitem->rect.
587 ** Windows will leave all drawing to the application except for
588 ** the popup-menu arrow. Windows always draws that itself, after
589 ** the menu owner has finished drawing.
593 dis
.CtlType
= ODT_MENU
;
595 dis
.itemID
= Item
->wID
;
596 dis
.itemData
= (DWORD
)Item
->dwItemData
;
598 if (0 != (Item
->fState
& MF_CHECKED
))
600 dis
.itemState
|= ODS_CHECKED
;
602 if (0 != (Item
->fState
& MF_GRAYED
))
604 dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
606 if (0 != (Item
->fState
& MF_HILITE
))
608 dis
.itemState
|= ODS_SELECTED
;
610 dis
.itemAction
= Action
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
611 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
614 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
615 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
616 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
617 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
619 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
620 /* Draw the popup-menu arrow */
621 if (0 != (Item
->fType
& MF_POPUP
))
623 HDC DcMem
= CreateCompatibleDC(Dc
);
626 OrigBitmap
= SelectObject(DcMem
, StdMnArrow
);
627 BitBlt(Dc
, Rect
.right
- ArrowBitmapWidth
- 1,
628 ((Rect
.top
+ Rect
.bottom
) - ArrowBitmapHeight
) / 2,
629 ArrowBitmapWidth
, ArrowBitmapHeight
,
630 DcMem
, 0, 0, SRCCOPY
);
631 SelectObject(DcMem
, OrigBitmap
);
637 TRACE("rect={%ld,%ld,%ld,%ld}\n", Item
->Rect
.left
, Item
->Rect
.top
,
638 Item
->Rect
.right
, Item
->Rect
.bottom
);
640 if (MenuBar
&& 0 != (Item
->fType
& MF_SEPARATOR
))
645 if (Item
->fState
& MF_HILITE
)
649 InflateRect (&Rect
, -1, -1);
650 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
651 InflateRect (&Rect
, 1, 1);
652 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
658 DrawEdge(Dc
, &Rect
, BDR_SUNKENOUTER
, BF_RECT
);
662 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
668 FillRect(Dc
, &Rect
, GetSysColorBrush(bkgnd
));
671 SetBkMode(Dc
, TRANSPARENT
);
673 /* vertical separator */
674 if (! MenuBar
&& 0 != (Item
->fType
& MF_MENUBARBREAK
))
680 rc
.bottom
= Height
- 3;
683 oldPen
= SelectObject( Dc
, GetSysColorPen(COLOR_BTNSHADOW
) );
684 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
685 LineTo( Dc
, rc
.left
, rc
.bottom
);
686 SelectObject( Dc
, oldPen
);
689 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
692 /* horizontal separator */
693 if (0 != (Item
->fType
& MF_SEPARATOR
))
699 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
702 oldPen
= SelectObject( Dc
, GetSysColorPen(COLOR_BTNSHADOW
) );
703 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
704 LineTo( Dc
, rc
.right
, rc
.top
);
705 SelectObject( Dc
, oldPen
);
708 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_TOP
);
713 /* helper lines for debugging */
714 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
715 FrameRect(Dc
, &Rect
, GetStockObject(BLACK_BRUSH
));
716 SelectObject(Dc
, GetSysColorPen(COLOR_WINDOWFRAME
));
717 MoveToEx(Dc
, Rect
.left
, (Rect
.top
+ Rect
.bottom
) / 2, NULL
);
718 LineTo(Dc
, Rect
.right
, (Rect
.top
+ Rect
.bottom
) / 2);
723 INT y
= Rect
.top
+ Rect
.bottom
;
725 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
726 UINT CheckBitmapHeight
= GetSystemMetrics(SM_CYMENUCHECK
);
728 /* Draw the check mark
731 * Custom checkmark bitmaps are monochrome but not always 1bpp.
733 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
735 HBITMAP bm
= 0 != (Item
->fState
& MF_CHECKED
) ? Item
->hbmpChecked
: Item
->hbmpUnchecked
;
736 if (NULL
!= bm
) /* we have a custom bitmap */
738 HDC DcMem
= CreateCompatibleDC(Dc
);
739 SelectObject(DcMem
, bm
);
740 BitBlt(Dc
, Rc
.left
, (y
- CheckBitmapHeight
) / 2,
741 CheckBitmapWidth
, CheckBitmapHeight
,
742 DcMem
, 0, 0, SRCCOPY
);
746 else if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
749 HBITMAP bm
= CreateBitmap(CheckBitmapWidth
, CheckBitmapHeight
, 1, 1, NULL
);
750 HDC DcMem
= CreateCompatibleDC(Dc
);
751 SelectObject(DcMem
, bm
);
752 SetRect( &r
, 0, 0, CheckBitmapWidth
, CheckBitmapHeight
);
753 DrawFrameControl(DcMem
, &r
, DFC_MENU
,
754 0 != (Item
->fType
& MFT_RADIOCHECK
) ?
755 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
756 BitBlt(Dc
, Rc
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
757 DcMem
, 0, 0, SRCCOPY
);
763 if ((Item
->hbmpItem
)&& !( checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
765 MenuDrawBitmapItem(Dc
, Item
, &Rect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
767 /* Draw the popup-menu arrow */
768 if (0 != (Item
->fType
& MF_POPUP
))
770 HDC DcMem
= CreateCompatibleDC(Dc
);
773 OrigBitmap
= SelectObject(DcMem
, StdMnArrow
);
774 BitBlt(Dc
, Rect
.right
- ArrowBitmapWidth
- 1,
775 (y
- ArrowBitmapHeight
) / 2,
776 ArrowBitmapWidth
, ArrowBitmapHeight
,
777 DcMem
, 0, 0, SRCCOPY
);
778 SelectObject(DcMem
, OrigBitmap
);
782 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
783 Rect
.left
+= CheckBitmapWidth
;
784 Rect
.right
-= ArrowBitmapWidth
;
786 else if (Item
->hbmpItem
) /* Draw the bitmap */
788 MenuDrawBitmapItem(Dc
, Item
, &Rect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
791 /* No bitmap - process text if present */
795 HFONT FontOld
= NULL
;
797 UINT uFormat
= MenuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
798 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
800 if( !(MenuInfo
->dwStyle
& MNS_CHECKORBMP
))
801 Rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
803 if (0 != (Item
->fState
& MFS_DEFAULT
))
805 FontOld
= SelectObject(Dc
, hMenuFontBold
);
810 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
811 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
813 if (Item
->hbmpItem
== HBMMENU_CALLBACK
|| MenuInfo
->maxBmpSize
.cx
!= 0 )
815 Rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
816 Rect
.right
-= MenuInfo
->maxBmpSize
.cx
;
819 Text
= (PWCHAR
) Item
->dwTypeData
;
822 for (i
= 0; L
'\0' != Text
[i
]; i
++)
824 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
831 if (0 != (Item
->fState
& MF_GRAYED
))
833 if (0 == (Item
->fState
& MF_HILITE
))
835 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
836 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
837 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
838 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
840 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
843 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
845 /* paint the shortcut text */
846 if (! MenuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
848 if (L
'\t' == Text
[i
])
850 Rect
.left
= Item
->XTab
;
851 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
855 Rect
.right
= Item
->XTab
;
856 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
859 if (0 != (Item
->fState
& MF_GRAYED
))
861 if (0 == (Item
->fState
& MF_HILITE
))
863 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
864 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
865 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
866 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
868 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
870 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
875 SelectObject(Dc
, FontOld
);
880 /***********************************************************************
883 * Paint a popup menu.
886 MenuDrawPopupMenu(HWND Wnd
, HDC Dc
, HMENU Menu
)
888 HBRUSH PrevBrush
= NULL
;
891 ROSMENUINFO MenuInfo
;
892 ROSMENUITEMINFO ItemInfo
;
895 TRACE("wnd=%x dc=%x menu=%x\n", Wnd
, Dc
, Menu
);
897 GetClientRect(Wnd
, &Rect
);
899 if (NULL
!= (PrevBrush
= SelectObject(Dc
, GetSysColorBrush(COLOR_MENU
)))
900 && NULL
!= SelectObject(Dc
, hMenuFont
))
902 Rectangle(Dc
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
904 PrevPen
= SelectObject(Dc
, GetStockObject(NULL_PEN
));
907 BOOL flat_menu
= FALSE
;
909 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
911 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
913 DrawEdge(Dc
, &Rect
, EDGE_RAISED
, BF_RECT
);
915 /* draw menu items */
917 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 != MenuInfo
.MenuItemCount
)
919 MenuInitRosMenuItemInfo(&ItemInfo
);
921 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
923 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
925 MenuDrawMenuItem(Wnd
, &MenuInfo
, MenuInfo
.WndOwner
, Dc
, &ItemInfo
,
926 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
930 MenuCleanupRosMenuItemInfo(&ItemInfo
);
935 SelectObject(Dc
, PrevBrush
);
940 static LRESULT WINAPI
941 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
943 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
949 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
950 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
954 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
955 return MA_NOACTIVATE
;
960 BeginPaint(Wnd
, &ps
);
961 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
970 /* zero out global pointer in case resident popup window was destroyed. */
980 if (0 == GetWindowLongPtrW(Wnd
, 0))
982 OutputDebugStringA("no menu to display\n");
987 SetWindowLongPtrW(Wnd
, 0, 0);
991 case MM_SETMENUHANDLE
:
992 SetWindowLongPtrW(Wnd
, 0, wParam
);
995 case MM_GETMENUHANDLE
:
996 return GetWindowLongPtrW(Wnd
, 0);
999 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1005 /**********************************************************************
1006 * MENUEX_ParseResource
1008 * Parse an extended menu resource and add items to the menu.
1009 * Return a pointer to the end of the resource.
1011 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
1013 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1021 mii
.cbSize
= sizeof(mii
);
1022 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
1023 mii
.fType
= GET_DWORD(res
);
1024 res
+= sizeof(DWORD
);
1025 mii
.fState
= GET_DWORD(res
);
1026 res
+= sizeof(DWORD
);
1027 mii
.wID
= GET_DWORD(res
);
1028 res
+= sizeof(DWORD
);
1029 resinfo
= GET_WORD(res
);
1030 res
+= sizeof(WORD
);
1031 /* Align the text on a word boundary. */
1032 res
+= (~((int)res
- 1)) & 1;
1033 mii
.dwTypeData
= (LPWSTR
) res
;
1034 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1035 /* Align the following fields on a dword boundary. */
1036 res
+= (~((int)res
- 1)) & 3;
1038 if (resinfo
& 1) /* Pop-up? */
1040 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1041 res
+= sizeof(DWORD
);
1042 mii
.hSubMenu
= CreatePopupMenu();
1045 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1047 DestroyMenu(mii
.hSubMenu
);
1050 mii
.fMask
|= MIIM_SUBMENU
;
1051 mii
.fType
|= MF_POPUP
;
1052 mii
.wID
= (UINT
) mii
.hSubMenu
;
1054 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1056 mii
.fType
|= MF_SEPARATOR
;
1058 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1060 while (!(resinfo
& MF_END
));
1065 /**********************************************************************
1066 * MENU_ParseResource
1068 * Parse a standard menu resource and add items to the menu.
1069 * Return a pointer to the end of the resource.
1071 * NOTE: flags is equivalent to the mtOption field
1073 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1082 flags
= GET_WORD(res
);
1084 /* remove MF_END flag before passing it to AppendMenu()! */
1085 end
= (flags
& MF_END
);
1086 if(end
) flags
^= MF_END
;
1088 res
+= sizeof(WORD
);
1089 if(!(flags
& MF_POPUP
))
1092 res
+= sizeof(WORD
);
1096 res
+= strlen(str
) + 1;
1098 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1099 if (flags
& MF_POPUP
)
1101 hSubMenu
= CreatePopupMenu();
1102 if(!hSubMenu
) return NULL
;
1103 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1106 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1108 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1110 else /* Not a popup */
1113 flags
= MF_SEPARATOR
;
1115 if (flags
& MF_SEPARATOR
)
1117 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1118 flags
|= MF_GRAYED
| MF_DISABLED
;
1122 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1124 AppendMenuW(hMenu
, flags
, id
,
1125 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1134 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1137 Result
= (LRESULT
)LoadMenuW(User32Instance
, L
"SYSMENU");
1138 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1145 NONCLIENTMETRICSW ncm
;
1147 /* get the menu font */
1148 if(!hMenuFont
|| !hMenuFontBold
)
1150 ncm
.cbSize
= sizeof(ncm
);
1151 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1153 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1157 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1158 if(hMenuFont
== NULL
)
1160 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1164 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1165 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1166 if(hMenuFontBold
== NULL
)
1168 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1169 DeleteObject(hMenuFont
);
1184 DeleteObject(hMenuFont
);
1190 DeleteObject(hMenuFontBold
);
1191 hMenuFontBold
= NULL
;
1197 /***********************************************************************
1200 * Calculate the size of the menu item and store it in ItemInfo->rect.
1202 static void FASTCALL
1203 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, PROSMENUINFO MenuInfo
, HWND WndOwner
,
1204 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1208 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1210 TRACE("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1212 MenuCharSize
.cx
= GdiGetCharDimensions( Dc
, NULL
, &MenuCharSize
.cy
);
1214 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1216 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1219 ** Experimentation under Windows reveals that an owner-drawn
1220 ** menu is expected to return the size of the content part of
1221 ** the menu item, not including the checkmark nor the submenu
1222 ** arrow. Windows adds those values itself and returns the
1223 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1225 MEASUREITEMSTRUCT mis
;
1226 mis
.CtlType
= ODT_MENU
;
1228 mis
.itemID
= ItemInfo
->wID
;
1229 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1230 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1232 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1233 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1234 * width of a menufont character to the width of an owner-drawn menu.
1236 ItemInfo
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1240 /* under at least win95 you seem to be given a standard
1241 height for the menu and the height value is ignored */
1242 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1246 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1249 TRACE("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1253 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1255 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1257 ItemInfo
->Rect
.right
+= ArrowBitmapWidth
+ MenuCharSize
.cx
;
1263 if (ItemInfo
->hbmpItem
)
1267 if (!MenuBar
) /* hbmpItem */
1269 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1270 /* Keep the size of the bitmap in callback mode to be able
1271 * to draw it correctly */
1272 ItemInfo
->Rect
.right
= ItemInfo
->Rect
.left
+ Size
.cx
;
1273 if (MenuInfo
->maxBmpSize
.cx
< abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
||
1274 MenuInfo
->maxBmpSize
.cy
< abs(Size
.cy
))
1276 MenuInfo
->maxBmpSize
.cx
= abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
;
1277 MenuInfo
->maxBmpSize
.cy
= abs(Size
.cy
);
1279 MenuSetRosMenuInfo(MenuInfo
);
1280 ItemInfo
->Rect
.right
+= Size
.cx
+ 2;
1281 itemheight
= Size
.cy
+ 2;
1283 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1284 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1285 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1286 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1287 ItemInfo
->Rect
.right
+= ArrowBitmapWidth
;
1289 else /* hbmpItem & MenuBar */
1291 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1292 ItemInfo
->Rect
.right
+= Size
.cx
;
1293 if( ItemInfo
->Text
) ItemInfo
->Rect
.right
+= 2;
1294 itemheight
= Size
.cy
;
1296 /* Special case: Minimize button doesn't have a space behind it. */
1297 if (ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1298 ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1299 ItemInfo
->Rect
.right
-= 1;
1304 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1305 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1306 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1307 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1308 ItemInfo
->Rect
.right
+= ArrowBitmapWidth
;
1311 /* it must be a text item - unless it's the system menu */
1312 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && ItemInfo
->Text
)
1314 HFONT hfontOld
= NULL
;
1315 RECT rc
= ItemInfo
->Rect
;
1316 LONG txtheight
, txtwidth
;
1318 if ( ItemInfo
->fState
& MFS_DEFAULT
)
1320 hfontOld
= SelectObject( Dc
, hMenuFontBold
);
1324 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1325 DT_SINGLELINE
|DT_CALCRECT
);
1326 ItemInfo
->Rect
.right
+= rc
.right
- rc
.left
;
1327 itemheight
= max( max( itemheight
, txtheight
),
1328 GetSystemMetrics( SM_CYMENU
) - 1);
1329 ItemInfo
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1333 if ((p
= strchrW( ItemInfo
->dwTypeData
, '\t' )) != NULL
)
1337 int n
= (int)( p
- ItemInfo
->dwTypeData
);
1338 /* Item contains a tab (only meaningful in popup menus) */
1339 /* get text size before the tab */
1340 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, n
, &rc
,
1341 DT_SINGLELINE
|DT_CALCRECT
);
1342 txtwidth
= rc
.right
- rc
.left
;
1343 p
+= 1; /* advance past the Tab */
1344 /* get text size after the tab */
1345 tmpheight
= DrawTextW( Dc
, p
, -1, &tmprc
, DT_SINGLELINE
|DT_CALCRECT
);
1346 ItemInfo
->XTab
+= txtwidth
;
1347 txtheight
= max( txtheight
, tmpheight
);
1348 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1349 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1353 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1354 DT_SINGLELINE
|DT_CALCRECT
);
1355 txtwidth
= rc
.right
- rc
.left
;
1356 ItemInfo
->XTab
+= txtwidth
;
1358 ItemInfo
->Rect
.right
+= 2 + txtwidth
;
1359 itemheight
= max( itemheight
, max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1361 if (hfontOld
) SelectObject (Dc
, hfontOld
);
1365 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1367 ItemInfo
->Rect
.bottom
+= itemheight
;
1368 TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1371 /***********************************************************************
1372 * MenuPopupMenuCalcSize
1374 * Calculate the size of a popup menu.
1376 static void FASTCALL
1377 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1379 ROSMENUITEMINFO ItemInfo
;
1382 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1384 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1385 if (0 == MenuInfo
->MenuItemCount
)
1387 MenuSetRosMenuInfo(MenuInfo
);
1392 SelectObject(Dc
, hMenuFont
);
1397 MenuInfo
->maxBmpSize
.cx
= 0;
1398 MenuInfo
->maxBmpSize
.cy
= 0;
1400 MenuInitRosMenuItemInfo(&ItemInfo
);
1401 while (Start
< MenuInfo
->MenuItemCount
)
1406 MaxTab
= MaxTabWidth
= 0;
1408 /* Parse items until column break or end of menu */
1409 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1411 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1413 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1414 MenuSetRosMenuInfo(MenuInfo
);
1418 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1422 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1423 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1425 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1426 MenuSetRosMenuInfo(MenuInfo
);
1429 // Not sure here,, The patch from wine removes this.
1430 // if (0 != (ItemInfo.fType & MF_MENUBARBREAK))
1434 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1435 OrgY
= ItemInfo
.Rect
.bottom
;
1436 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1438 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1439 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1443 /* Finish the column (set all items to the largest width found) */
1444 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1447 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1449 ItemInfo
.Rect
.right
= MaxX
;
1450 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1452 ItemInfo
.XTab
= MaxTab
;
1454 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1458 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1461 MenuInfo
->Width
= MaxX
;
1463 /* space for 3d border */
1464 MenuInfo
->Height
+= 2;
1465 MenuInfo
->Width
+= 2;
1467 ReleaseDC(NULL
, Dc
);
1468 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1469 MenuSetRosMenuInfo(MenuInfo
);
1472 /***********************************************************************
1473 * MenuMenuBarCalcSize
1475 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1476 * height is off by 1 pixel which causes lengthy window relocations when
1477 * active document window is maximized/restored.
1479 * Calculate the size of the menu bar.
1481 static void FASTCALL
1482 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1484 ROSMENUITEMINFO ItemInfo
;
1485 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1487 if (NULL
== Rect
|| NULL
== MenuInfo
)
1491 if (0 == MenuInfo
->MenuItemCount
)
1496 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1497 Rect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1498 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1499 MenuInfo
->Height
= 0;
1500 MaxY
= Rect
->top
+ 1;
1504 MenuInfo
->maxBmpSize
.cx
= 0;
1505 MenuInfo
->maxBmpSize
.cy
= 0;
1507 MenuInitRosMenuItemInfo(&ItemInfo
);
1508 while (Start
< MenuInfo
->MenuItemCount
)
1510 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1512 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1518 /* Parse items until line break or end of menu */
1519 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1521 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1526 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1531 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1532 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1533 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1535 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1539 if (ItemInfo
.Rect
.right
> Rect
->right
)
1547 ItemInfo
.Rect
.right
= Rect
->right
;
1550 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1551 OrgX
= ItemInfo
.Rect
.right
;
1552 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1554 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1556 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1562 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1563 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1565 /* Finish the line (set all items to the largest height found) */
1568 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1570 ItemInfo
.Rect
.bottom
= MaxY
;
1571 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1576 Start
= i
; /* This works! */
1580 Rect
->bottom
= MaxY
;
1581 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1582 MenuSetRosMenuInfo(MenuInfo
);
1586 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1587 /* the last item (if several lines, only move the last line) */
1588 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1590 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1593 OrgY
= ItemInfo
.Rect
.top
;
1595 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1601 if (ItemInfo
.Rect
.top
!= OrgY
)
1603 break; /* Other line */
1605 if (OrgX
<= ItemInfo
.Rect
.right
)
1607 break; /* Too far right already */
1609 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1610 ItemInfo
.Rect
.right
= OrgX
;
1611 OrgX
= ItemInfo
.Rect
.left
;
1612 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1613 if (HelpPos
+ 1 <= i
&&
1614 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1616 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1622 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1625 /***********************************************************************
1626 * DrawMenuBarTemp (USER32.@)
1630 * called by W98SE desk.cpl Control Panel Applet
1632 * Not 100% sure about the param names, but close.
1637 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1639 ROSMENUINFO MenuInfo
;
1640 ROSMENUITEMINFO ItemInfo
;
1642 HFONT FontOld
= NULL
;
1643 BOOL flat_menu
= FALSE
;
1645 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1649 Menu
= GetMenu(Wnd
);
1657 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1659 return GetSystemMetrics(SM_CYMENU
);
1662 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1664 FontOld
= SelectObject(DC
, Font
);
1666 if (0 == MenuInfo
.Height
)
1668 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1671 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1673 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
1675 SelectObject(DC
, GetSysColorPen(COLOR_3DFACE
));
1676 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1677 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1679 if (0 == MenuInfo
.MenuItemCount
)
1681 SelectObject(DC
, FontOld
);
1682 return GetSystemMetrics(SM_CYMENU
);
1685 MenuInitRosMenuItemInfo(&ItemInfo
);
1686 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1688 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1690 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1691 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1694 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1696 SelectObject(DC
, FontOld
);
1698 return MenuInfo
.Height
;
1702 /***********************************************************************
1705 * Paint a menu bar. Returns the height of the menu bar.
1706 * called from [windows/nonclient.c]
1708 UINT
MenuDrawMenuBar(HDC DC
, LPRECT Rect
, HWND Wnd
, BOOL SuppressDraw
)
1710 ROSMENUINFO MenuInfo
;
1711 HFONT FontOld
= NULL
;
1712 HMENU Menu
= GetMenu(Wnd
);
1714 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1716 return GetSystemMetrics(SM_CYMENU
);
1721 FontOld
= SelectObject(DC
, hMenuFont
);
1723 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1725 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1727 if (NULL
!= FontOld
)
1729 SelectObject(DC
, FontOld
);
1731 return MenuInfo
.Height
;
1735 return DrawMenuBarTemp(Wnd
, DC
, Rect
, Menu
, NULL
);
1739 /***********************************************************************
1742 static BOOL FASTCALL
1743 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1745 TRACE("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1749 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1750 if (0 == (Flags
& TPM_NONOTIFY
))
1752 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1755 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1757 if (0 == (Flags
& TPM_NONOTIFY
))
1759 ROSMENUINFO MenuInfo
;
1761 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1763 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
1765 if (0 == MenuInfo
.Height
)
1767 /* app changed/recreated menu bar entries in WM_INITMENU
1768 Recalculate menu sizes else clicks will not work */
1769 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1770 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1773 /* This makes the menus of applications built with Delphi work.
1774 * It also enables menus to be displayed in more than one window,
1775 * but there are some bugs left that need to be fixed in this case.
1777 if(MenuInfo
.Self
== Menu
)
1780 MenuSetRosMenuInfo(&MenuInfo
);
1788 /***********************************************************************
1791 * Display a popup menu.
1793 static BOOL FASTCALL
1794 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1795 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1797 ROSMENUINFO MenuInfo
;
1798 ROSMENUITEMINFO ItemInfo
;
1801 TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1802 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1804 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1809 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1811 MenuInitRosMenuItemInfo(&ItemInfo
);
1812 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1814 ItemInfo
.fMask
|= MIIM_STATE
;
1815 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1816 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1818 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1819 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1822 /* store the owner for DrawItem */
1823 MenuInfo
.WndOwner
= WndOwner
;
1824 MenuSetRosMenuInfo(&MenuInfo
);
1826 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1828 /* adjust popup menu pos so that it fits within the desktop */
1830 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1831 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1833 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1835 if (0 != XAnchor
&& X
>= Width
- XAnchor
)
1837 X
-= Width
- XAnchor
;
1839 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1841 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1849 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1851 if (0 != YAnchor
&& Y
>= Height
+ YAnchor
)
1853 Y
-= Height
+ YAnchor
;
1855 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1857 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
1866 /* NOTE: In Windows, top menu popup is not owned. */
1867 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
1868 WS_POPUP
, X
, Y
, Width
, Height
,
1869 WndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(WndOwner
, GWLP_HINSTANCE
),
1870 (LPVOID
) MenuInfo
.Self
);
1871 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
1875 if (NULL
== TopPopup
)
1877 TopPopup
= MenuInfo
.Wnd
;
1880 /* Display the window */
1881 SetWindowPos(MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1882 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1883 UpdateWindow(MenuInfo
.Wnd
);
1888 /***********************************************************************
1891 * Find a Sub menu. Return the position of the submenu, and modifies
1892 * *hmenu in case it is found in another sub-menu.
1893 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
1895 static UINT FASTCALL
1896 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
1898 ROSMENUINFO MenuInfo
;
1899 ROSMENUITEMINFO ItemInfo
;
1904 if ((HMENU
) 0xffff == *Menu
1905 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
1907 return NO_SELECTED_ITEM
;
1910 MenuInitRosMenuItemInfo(&ItemInfo
);
1911 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1913 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1915 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1916 return NO_SELECTED_ITEM
;
1918 if (0 == (ItemInfo
.fType
& MF_POPUP
))
1922 if (ItemInfo
.hSubMenu
== SubTarget
)
1924 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1927 SubMenu
= ItemInfo
.hSubMenu
;
1928 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
1929 if (NO_SELECTED_ITEM
!= Pos
)
1935 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1937 return NO_SELECTED_ITEM
;
1940 /***********************************************************************
1943 static void FASTCALL
1944 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
1945 BOOL SendMenuSelect
, HMENU TopMenu
)
1948 ROSMENUITEMINFO ItemInfo
;
1949 ROSMENUINFO TopMenuInfo
;
1952 TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
1954 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
1959 if (MenuInfo
->FocusedItem
== Index
)
1964 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
1966 Dc
= GetDC(MenuInfo
->Wnd
);
1970 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1973 if (NULL
== TopPopup
)
1975 TopPopup
= MenuInfo
->Wnd
;
1978 SelectObject(Dc
, hMenuFont
);
1979 MenuInitRosMenuItemInfo(&ItemInfo
);
1980 /* Clear previous highlighted item */
1981 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1983 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1985 ItemInfo
.fMask
|= MIIM_STATE
;
1986 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1987 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1989 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
1990 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1994 /* Highlight new item (if any) */
1995 MenuInfo
->FocusedItem
= Index
;
1996 MenuSetRosMenuInfo(MenuInfo
);
1997 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1999 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2001 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2003 ItemInfo
.fMask
|= MIIM_STATE
;
2004 ItemInfo
.fState
|= MF_HILITE
;
2005 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2006 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
2007 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2012 SendMessageW(WndOwner
, WM_MENUSELECT
,
2013 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
2014 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
2015 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
2019 else if (SendMenuSelect
)
2021 if (NULL
!= TopMenu
)
2023 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
2024 if (NO_SELECTED_ITEM
!= Pos
)
2026 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
2027 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
2029 SendMessageW(WndOwner
, WM_MENUSELECT
,
2030 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
2032 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
2038 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2039 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2042 /***********************************************************************
2045 * Moves currently selected item according to the Offset parameter.
2046 * If there is no selection then it should select the last item if
2047 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2049 static void FASTCALL
2050 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2053 ROSMENUITEMINFO ItemInfo
;
2056 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2058 /* Prevent looping */
2059 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
2061 else if (Offset
< -1)
2063 else if (Offset
> 1)
2066 MenuInitRosMenuItemInfo(&ItemInfo
);
2068 OrigPos
= MenuInfo
->FocusedItem
;
2069 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2076 i
= MenuInfo
->FocusedItem
;
2083 /* Clip and wrap around */
2086 i
= MenuInfo
->MenuItemCount
- 1;
2088 else if (i
>= MenuInfo
->MenuItemCount
)
2092 /* If this is a good candidate; */
2093 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2094 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2096 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2097 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2100 } while (i
!= OrigPos
);
2103 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2106 /***********************************************************************
2107 * MenuInitSysMenuPopup
2109 * Grey the appropriate items in System menu.
2112 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2120 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2121 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2122 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2123 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2124 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2125 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2126 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2127 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2128 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2129 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2130 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2132 /* The menu item must keep its state if it's disabled */
2135 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2138 /* Set default menu item */
2139 if(Style
& WS_MINIMIZE
)
2141 DefItem
= SC_RESTORE
;
2145 if(HitTest
== HTCAPTION
)
2147 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2155 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2156 mii
.fMask
|= MIIM_STATE
;
2157 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2158 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2163 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2166 /***********************************************************************
2169 * Display the sub-menu of the selected item of this menu.
2170 * Return the handle of the submenu, or menu if no submenu to display.
2172 static HMENU FASTCALL
2173 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2175 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2177 ROSMENUITEMINFO ItemInfo
;
2178 ROSMENUINFO SubMenuInfo
;
2182 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2184 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2186 return MenuInfo
->Self
;
2189 MenuInitRosMenuItemInfo(&ItemInfo
);
2190 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2192 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2193 return MenuInfo
->Self
;
2195 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2197 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2198 return MenuInfo
->Self
;
2201 /* message must be sent before using item,
2202 because nearly everything may be changed by the application ! */
2204 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2205 if (0 == (Flags
& TPM_NONOTIFY
))
2207 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2208 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2211 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2213 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2214 return MenuInfo
->Self
;
2216 Rect
= ItemInfo
.Rect
;
2218 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2219 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2221 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2223 Dc
= GetDC(MenuInfo
->Wnd
);
2227 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2230 SelectObject(Dc
, hMenuFont
);
2231 ItemInfo
.fMask
|= MIIM_STATE
;
2232 ItemInfo
.fState
|= MF_HILITE
;
2233 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2234 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2235 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2236 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2239 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2240 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2242 ItemInfo
.Rect
= Rect
;
2245 ItemInfo
.fMask
|= MIIM_STATE
;
2246 ItemInfo
.fState
|= MF_MOUSESELECT
;
2247 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2249 if (IS_SYSTEM_MENU(MenuInfo
))
2251 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongW(MenuInfo
->Wnd
, GWL_STYLE
),
2252 GetClassLongW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2254 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2255 Rect
.top
= Rect
.bottom
;
2256 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2257 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2261 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2262 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2264 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2265 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2266 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2267 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2268 - GetSystemMetrics(SM_CYBORDER
);
2272 Rect
.left
+= ItemInfo
.Rect
.left
;
2273 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2274 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2275 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2279 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2280 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2281 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2283 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2286 Ret
= ItemInfo
.hSubMenu
;
2287 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2292 /***********************************************************************
2295 * Hide the sub-popup menus of this menu.
2297 static void FASTCALL
2298 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2300 ROSMENUINFO SubMenuInfo
;
2301 ROSMENUITEMINFO ItemInfo
;
2303 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2305 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2307 MenuInitRosMenuItemInfo(&ItemInfo
);
2308 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2309 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2310 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2311 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2313 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2316 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2317 ItemInfo
.fMask
|= MIIM_STATE
;
2318 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2319 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2321 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2322 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2323 DestroyWindow(SubMenuInfo
.Wnd
);
2324 SubMenuInfo
.Wnd
= NULL
;
2325 MenuSetRosMenuInfo(&SubMenuInfo
);
2330 /***********************************************************************
2331 * MenuSwitchTracking
2333 * Helper function for menu navigation routines.
2335 static void FASTCALL
2336 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2338 ROSMENUINFO TopMenuInfo
;
2340 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2342 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2343 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2344 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2346 /* both are top level menus (system and menu-bar) */
2347 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2348 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2349 Mt
->TopMenu
= PtMenuInfo
->Self
;
2353 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2356 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2359 /***********************************************************************
2360 * MenuExecFocusedItem
2362 * Execute a menu item (for instance when user pressed Enter).
2363 * Return the wID of the executed item. Otherwise, -1 indicating
2364 * that no menu item was executed, -2 if a popup is shown;
2365 * Have to receive the flags for the TrackPopupMenu options to avoid
2366 * sending unwanted message.
2370 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2372 ROSMENUITEMINFO ItemInfo
;
2375 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2377 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2382 MenuInitRosMenuItemInfo(&ItemInfo
);
2383 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2385 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2389 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2391 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2393 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2394 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2396 /* If TPM_RETURNCMD is set you return the id, but
2397 do not send a message to the owner */
2398 if (0 == (Flags
& TPM_RETURNCMD
))
2400 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2402 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2403 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2407 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2408 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2409 MenuInfo
->FocusedItem
,
2410 (LPARAM
)MenuInfo
->Self
);
2412 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2416 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2422 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2429 /***********************************************************************
2432 * Return TRUE if we can go on with menu tracking.
2434 static BOOL FASTCALL
2435 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2438 ROSMENUINFO MenuInfo
;
2439 ROSMENUITEMINFO Item
;
2441 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2445 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2449 if (IS_SYSTEM_MENU(&MenuInfo
))
2455 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2457 MenuInitRosMenuItemInfo(&Item
);
2458 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2460 MenuCleanupRosMenuItemInfo(&Item
);
2464 if (!(Item
.fType
& MF_SEPARATOR
) &&
2465 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2467 if (MenuInfo
.FocusedItem
!= Index
)
2469 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2472 /* If the popup menu is not already "popped" */
2473 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2475 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2479 MenuCleanupRosMenuItemInfo(&Item
);
2484 /* else the click was on the menu bar, finish the tracking */
2489 /***********************************************************************
2492 * Return the value of MenuExecFocusedItem if
2493 * the selected item was not a popup. Else open the popup.
2494 * A -1 return value indicates that we go on with menu tracking.
2498 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2501 ROSMENUINFO MenuInfo
;
2502 ROSMENUITEMINFO ItemInfo
;
2504 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2509 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2514 if (! IS_SYSTEM_MENU(&MenuInfo
))
2516 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2518 MenuInitRosMenuItemInfo(&ItemInfo
);
2519 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2520 MenuInfo
.FocusedItem
== Id
)
2522 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2524 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2525 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2526 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2528 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2530 /* If we are dealing with the top-level menu */
2531 /* and this is a click on an already "popped" item: */
2532 /* Stop the menu tracking and close the opened submenus */
2533 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2535 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2539 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2540 MenuInfo
.TimeToHide
= TRUE
;
2541 MenuSetRosMenuInfo(&MenuInfo
);
2547 /***********************************************************************
2550 * Walks menu chain trying to find a menu pt maps to.
2552 static HMENU FASTCALL
2553 MenuPtMenu(HMENU Menu
, POINT Pt
)
2555 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2556 ROSMENUINFO MenuInfo
;
2557 ROSMENUITEMINFO ItemInfo
;
2561 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2566 /* try subpopup first (if any) */
2567 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2569 MenuInitRosMenuItemInfo(&ItemInfo
);
2570 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2571 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2572 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2574 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2577 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2581 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2584 /* check the current window (avoiding WM_HITTEST) */
2585 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2586 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2588 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2593 else if (HTSYSMENU
== Ht
)
2595 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2597 else if (HTMENU
== Ht
)
2599 Ret
= GetMenu(MenuInfo
.Wnd
);
2605 /***********************************************************************
2608 * Return TRUE if we can go on with menu tracking.
2610 static BOOL FASTCALL
2611 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2614 ROSMENUINFO MenuInfo
;
2615 ROSMENUITEMINFO ItemInfo
;
2619 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2623 if (IS_SYSTEM_MENU(&MenuInfo
))
2629 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2634 Index
= NO_SELECTED_ITEM
;
2637 if (NO_SELECTED_ITEM
== Index
)
2639 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2640 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2642 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2646 else if (MenuInfo
.FocusedItem
!= Index
)
2648 MenuInitRosMenuItemInfo(&ItemInfo
);
2649 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2650 !(ItemInfo
.fType
& MF_SEPARATOR
))
2652 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2653 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2654 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2656 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2662 /******************************************************************************
2664 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2666 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2669 PROSMENUITEMINFO MenuItems
;
2671 i
= MenuInfo
->FocusedItem
;
2672 if (NO_SELECTED_ITEM
== i
)
2677 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2679 return NO_SELECTED_ITEM
;
2682 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2684 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2690 return NO_SELECTED_ITEM
;
2693 /******************************************************************************
2695 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2697 static UINT FASTCALL
2698 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2701 PROSMENUITEMINFO MenuItems
;
2703 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2705 return NO_SELECTED_ITEM
;
2708 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2710 return NO_SELECTED_ITEM
;
2713 /* Find the start of the column */
2715 for (i
= MenuInfo
->FocusedItem
;
2716 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2724 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2725 return NO_SELECTED_ITEM
;
2728 for (--i
; 0 != i
; --i
)
2730 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2736 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2737 TRACE("ret %d.\n", i
);
2742 /***********************************************************************
2745 * Return the handle of the selected sub-popup menu (if any).
2747 static HMENU FASTCALL
2748 MenuGetSubPopup(HMENU Menu
)
2750 ROSMENUINFO MenuInfo
;
2751 ROSMENUITEMINFO ItemInfo
;
2753 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2754 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2759 MenuInitRosMenuItemInfo(&ItemInfo
);
2760 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2762 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2765 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2767 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2768 return ItemInfo
.hSubMenu
;
2771 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2775 /***********************************************************************
2778 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2780 static LRESULT FASTCALL
2781 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2783 ROSMENUINFO TopMenuInfo
;
2784 ROSMENUINFO MenuInfo
;
2786 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2788 return (LRESULT
) FALSE
;
2791 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2792 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2794 MDINEXTMENU NextMenu
;
2799 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2800 NextMenu
.hmenuNext
= NULL
;
2801 NextMenu
.hwndNext
= NULL
;
2802 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2804 TRACE("%p [%p] -> %p [%p]\n",
2805 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2807 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2809 DWORD Style
= GetWindowLongW(Mt
->OwnerWnd
, GWL_STYLE
);
2810 NewWnd
= Mt
->OwnerWnd
;
2811 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2813 /* switch to the menu bar */
2815 if (0 != (Style
& WS_CHILD
)
2816 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2823 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2827 Id
= MenuInfo
.MenuItemCount
- 1;
2830 else if (0 != (Style
& WS_SYSMENU
))
2832 /* switch to the system menu */
2833 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2840 else /* application returned a new menu to switch to */
2842 NewMenu
= NextMenu
.hmenuNext
;
2843 NewWnd
= NextMenu
.hwndNext
;
2845 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2847 DWORD Style
= GetWindowLongW(NewWnd
, GWL_STYLE
);
2849 if (0 != (Style
& WS_SYSMENU
)
2850 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2852 /* get the real system menu */
2853 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2855 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2857 /* FIXME: Not sure what to do here;
2858 * perhaps try to track NewMenu as a popup? */
2860 WARN(" -- got confused.\n");
2870 if (NewMenu
!= Mt
->TopMenu
)
2872 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2874 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2876 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2880 if (NewWnd
!= Mt
->OwnerWnd
)
2882 Mt
->OwnerWnd
= NewWnd
;
2883 SetCapture(Mt
->OwnerWnd
);
2884 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2887 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2888 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2890 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2899 /***********************************************************************
2902 * The idea is not to show the popup if the next input message is
2903 * going to hide it anyway.
2905 static BOOL FASTCALL
2906 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2910 Msg
.hwnd
= Mt
->OwnerWnd
;
2912 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2913 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2918 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2919 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2921 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2922 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2923 if (WM_KEYDOWN
== Msg
.message
2924 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2926 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2933 /* failures go through this */
2934 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2939 /***********************************************************************
2942 * Handle a VK_ESCAPE key event in a menu.
2944 static BOOL FASTCALL
2945 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2947 BOOL EndMenu
= TRUE
;
2948 ROSMENUINFO MenuInfo
;
2949 HMENU MenuTmp
, MenuPrev
;
2951 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2953 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2954 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2956 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2958 /* close topmost popup */
2959 while (MenuTmp
!= Mt
->CurrentMenu
)
2962 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2965 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2967 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
2969 Mt
->CurrentMenu
= MenuPrev
;
2977 /***********************************************************************
2980 * Handle a VK_LEFT key event in a menu.
2982 static void FASTCALL
2983 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2985 ROSMENUINFO MenuInfo
;
2986 ROSMENUINFO TopMenuInfo
;
2987 ROSMENUINFO PrevMenuInfo
;
2988 HMENU MenuTmp
, MenuPrev
;
2991 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2993 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2998 /* Try to move 1 column left (if possible) */
2999 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3001 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3003 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3008 /* close topmost popup */
3009 while (MenuTmp
!= Mt
->CurrentMenu
)
3012 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3015 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3019 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
3020 Mt
->CurrentMenu
= MenuPrev
;
3022 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3026 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3028 /* move menu bar selection if no more popups are left */
3030 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
3032 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3035 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3037 /* A sublevel menu was displayed - display the next one
3038 * unless there is another displacement coming up */
3040 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3041 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3043 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3050 /***********************************************************************
3053 * Handle a VK_RIGHT key event in a menu.
3055 static void FASTCALL
3056 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3059 ROSMENUINFO MenuInfo
;
3060 ROSMENUINFO CurrentMenuInfo
;
3063 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3064 Mt
->CurrentMenu
, Mt
->TopMenu
);
3066 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3070 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3072 /* If already displaying a popup, try to display sub-popup */
3074 MenuTmp
= Mt
->CurrentMenu
;
3075 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3077 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3080 /* if subpopup was displayed then we are done */
3081 if (MenuTmp
!= Mt
->CurrentMenu
)
3087 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3092 /* Check to see if there's another column */
3093 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3095 TRACE("Going to %d.\n", NextCol
);
3096 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3098 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3103 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3105 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3107 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3108 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3115 /* try to move to the next item */
3116 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
3118 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3121 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3123 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3124 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3126 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3133 /***********************************************************************
3136 * Find the menu item selected by a key press.
3137 * Return item id, -1 if none, -2 if we should close the menu.
3139 static UINT FASTCALL
3140 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
3141 WCHAR Key
, BOOL ForceMenuChar
)
3143 ROSMENUINFO SysMenuInfo
;
3144 PROSMENUITEMINFO Items
, ItemInfo
;
3148 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
3150 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
3152 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
3154 MenuInfo
= &SysMenuInfo
;
3162 if (NULL
!= MenuInfo
)
3164 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
3168 if (! ForceMenuChar
)
3170 Key
= toupperW(Key
);
3172 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
3174 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
3176 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
3179 p
= strchrW(p
+ 2, '&');
3181 while (NULL
!= p
&& L
'&' == p
[1]);
3182 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
3190 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
3191 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
3192 if (2 == HIWORD(MenuChar
))
3194 return LOWORD(MenuChar
);
3196 if (1 == HIWORD(MenuChar
))
3205 /***********************************************************************
3208 * Menu tracking code.
3211 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3212 HWND Wnd
, const RECT
*Rect
)
3215 ROSMENUINFO MenuInfo
;
3216 ROSMENUITEMINFO ItemInfo
;
3218 INT ExecutedMenuId
= -1;
3220 BOOL EnterIdleSent
= FALSE
;
3223 Mt
.CurrentMenu
= Menu
;
3229 TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3230 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3231 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3234 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3239 if (0 != (Flags
& TPM_BUTTONDOWN
))
3241 /* Get the result in order to start the tracking or not */
3242 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3243 fEndMenu
= ! fRemove
;
3246 SetCapture(Mt
.OwnerWnd
);
3247 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
.OwnerWnd
);
3251 /* we have to keep the message in the queue until it's
3252 * clear that menu loop is not over yet. */
3256 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3258 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3262 /* remove the message from the queue */
3263 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3267 if (! EnterIdleSent
)
3269 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3270 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3271 EnterIdleSent
= TRUE
;
3272 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3278 /* check if EndMenu() tried to cancel us, by posting this message */
3279 if (WM_CANCELMODE
== Msg
.message
)
3281 /* we are now out of the loop */
3284 /* remove the message from the queue */
3285 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3287 /* break out of internal loop, ala ESCAPE */
3291 TranslateMessage(&Msg
);
3294 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3296 EnterIdleSent
= FALSE
;
3300 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3303 * Use the mouse coordinates in lParam instead of those in the MSG
3304 * struct to properly handle synthetic messages. They are already
3305 * in screen coordinates.
3307 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3308 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3310 /* Find a menu for this mouse event */
3311 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3315 /* no WM_NC... messages in captured state */
3317 case WM_RBUTTONDBLCLK
:
3318 case WM_RBUTTONDOWN
:
3319 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3324 case WM_LBUTTONDBLCLK
:
3325 case WM_LBUTTONDOWN
:
3326 /* If the message belongs to the menu, removes it from the queue */
3327 /* Else, end menu tracking */
3328 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3329 fEndMenu
= ! fRemove
;
3333 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3339 /* Check if a menu was selected by the mouse */
3342 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3344 /* End the loop if ExecutedMenuId is an item ID */
3345 /* or if the job was done (ExecutedMenuId = 0). */
3346 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3350 /* No menu was selected by the mouse */
3351 /* if the function was called by TrackPopupMenu, continue
3352 with the menu tracking. If not, stop it */
3353 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3360 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3364 } /* switch(Msg.message) - mouse */
3366 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3368 fRemove
= TRUE
; /* Keyboard messages are always removed */
3380 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3382 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3388 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3390 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3391 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3395 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3396 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3398 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3400 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3402 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3406 else /* otherwise try to move selection */
3408 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3414 MenuKeyLeft(&Mt
, Flags
);
3418 MenuKeyRight(&Mt
, Flags
);
3422 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3428 hi
.cbSize
= sizeof(HELPINFO
);
3429 hi
.iContextType
= HELPINFO_MENUITEM
;
3430 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3432 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3438 MenuInitRosMenuItemInfo(&ItemInfo
);
3439 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3440 MenuInfo
.FocusedItem
,
3443 hi
.iCtrlId
= ItemInfo
.wID
;
3449 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3452 hi
.hItemHandle
= Menu
;
3453 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3454 hi
.MousePos
= Msg
.pt
;
3455 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3462 break; /* WM_KEYDOWN */
3469 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3473 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3475 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3476 fEndMenu
= (ExecutedMenuId
!= -2);
3480 /* Hack to avoid control chars. */
3481 /* We will find a better way real soon... */
3482 if (Msg
.wParam
< 32)
3487 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3488 LOWORD(Msg
.wParam
), FALSE
);
3489 if ((UINT
) -2 == Pos
)
3493 else if ((UINT
) -1 == Pos
)
3499 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3500 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3501 fEndMenu
= (-2 != ExecutedMenuId
);
3505 } /* switch(msg.message) - kbd */
3509 PeekMessageW( &Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3510 DispatchMessageW(&Msg
);
3519 /* finally remove message from the queue */
3521 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3523 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3527 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3531 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3532 SetCapture(NULL
); /* release the capture */
3534 /* If dropdown is still painted and the close box is clicked on
3535 then the menu will be destroyed as part of the DispatchMessage above.
3536 This will then invalidate the menu handle in Mt.hTopMenu. We should
3537 check for this first. */
3538 if (IsMenu(Mt
.TopMenu
))
3540 if (IsWindow(Mt
.OwnerWnd
))
3542 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3544 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3546 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3548 DestroyWindow(MenuInfo
.Wnd
);
3549 MenuInfo
.Wnd
= NULL
;
3551 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3554 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3557 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3559 /* Reset the variable for hiding menu */
3560 MenuInfo
.TimeToHide
= FALSE
;
3561 MenuSetRosMenuInfo(&MenuInfo
);
3565 /* The return value is only used by TrackPopupMenu */
3566 if (!(Flags
& TPM_RETURNCMD
)) return TRUE
;
3567 if (ExecutedMenuId
< 0) ExecutedMenuId
= 0;
3568 return ExecutedMenuId
;
3571 /***********************************************************************
3574 static BOOL FASTCALL
3575 MenuExitTracking(HWND Wnd
)
3577 TRACE("hwnd=%p\n", Wnd
);
3579 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3586 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3588 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3589 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3591 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, Pt
.x
, Pt
.y
);
3595 /* map point to parent client coordinates */
3596 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3597 if (Parent
!= GetDesktopWindow())
3599 ScreenToClient(Parent
, &Pt
);
3602 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3603 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3604 MenuExitTracking(Wnd
);
3610 MenuTrackKbdMenuBar(HWND hWnd
, UINT wParam
, WCHAR wChar
)
3612 UINT uItem
= NO_SELECTED_ITEM
;
3614 ROSMENUINFO MenuInfo
;
3615 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3617 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd
, wParam
, wChar
);
3619 /* find window that has a menu */
3621 while (!((GetWindowLongW( hWnd
, GWL_STYLE
) &
3622 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3623 if (!(hWnd
= GetAncestor( hWnd
, GA_PARENT
))) return;
3625 /* check if we have to track a system menu */
3627 hTrackMenu
= GetMenu( hWnd
);
3628 if (!hTrackMenu
|| IsIconic(hWnd
) || wChar
== ' ' )
3630 if (!(GetWindowLongW( hWnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3631 hTrackMenu
= NtUserGetSystemMenu(hWnd
, FALSE
);
3633 wParam
|= HTSYSMENU
; /* prevent item lookup */
3636 if (!IsMenu( hTrackMenu
)) return;
3638 MenuInitTracking( hWnd
, hTrackMenu
, FALSE
, wFlags
);
3640 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3645 if( wChar
&& wChar
!= ' ' )
3647 uItem
= MenuFindItemByKey( hWnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3648 if ( uItem
>= (UINT
)(-2) )
3650 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3651 /* schedule end of menu tracking */
3652 wFlags
|= TF_ENDMENU
;
3657 MenuSelectItem( hWnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3659 if (wParam
& HTSYSMENU
)
3661 /* prevent sysmenu activation for managed windows on Alt down/up */
3662 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3663 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3667 if( uItem
== NO_SELECTED_ITEM
)
3668 MenuMoveSelection( hWnd
, &MenuInfo
, ITEM_NEXT
);
3670 PostMessageW( hWnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3674 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hWnd
, NULL
);
3675 MenuExitTracking( hWnd
);
3681 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3682 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3684 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3686 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3687 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3688 * MFT_STRING is replaced by MIIM_STRING.
3689 * (So, I guess we should use MIIM_STRING only for strings?)
3691 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3693 * Based on wine, SetMenuItemInfo_common:
3694 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3695 * it will result in a error.
3696 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3697 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3704 LPMENUITEMINFOW mii
,
3711 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3713 if(Flags
& MF_BITMAP
)
3715 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3716 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3718 if (Flags
& MF_HELP
)
3720 /* increase ident */
3721 mii
->fType
|= MF_HELP
;
3724 else if(Flags
& MF_OWNERDRAW
)
3726 mii
->fType
|= MFT_OWNERDRAW
;
3727 mii
->fMask
|= MIIM_DATA
;
3728 mii
->dwItemData
= (DWORD
) NewItem
;
3730 else if (Flags
& MF_SEPARATOR
)
3732 mii
->fType
|= MFT_SEPARATOR
;
3733 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3734 Flags
|= MF_GRAYED
|MF_DISABLED
;
3736 else /* Default action MF_STRING. */
3738 /* Item beginning with a backspace is a help item */
3739 if (NewItem
!= NULL
)
3743 if (*NewItem
== '\b')
3745 mii
->fType
|= MF_HELP
;
3751 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3752 if (*NewItemA
== '\b')
3754 mii
->fType
|= MF_HELP
;
3756 NewItem
= (LPCWSTR
) NewItemA
;
3760 if (Flags
& MF_HELP
)
3761 mii
->fType
|= MF_HELP
;
3762 mii
->fMask
|= MIIM_STRING
;
3763 mii
->fType
|= MFT_STRING
; /* Zero */
3764 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3766 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3768 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3772 mii
->fType
|= MFT_SEPARATOR
;
3773 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3774 Flags
|= MF_GRAYED
|MF_DISABLED
;
3778 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3780 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3783 if(Flags
& MF_MENUBREAK
)
3785 mii
->fType
|= MFT_MENUBREAK
;
3787 else if(Flags
& MF_MENUBARBREAK
)
3789 mii
->fType
|= MFT_MENUBARBREAK
;
3792 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3794 if (Flags
& MF_GRAYED
)
3795 mii
->fState
|= MF_GRAYED
;
3797 if (Flags
& MF_DISABLED
)
3798 mii
->fState
|= MF_DISABLED
;
3800 mii
->fMask
|= MIIM_STATE
;
3802 else if (Flags
& MF_HILITE
)
3804 mii
->fState
|= MF_HILITE
;
3805 mii
->fMask
|= MIIM_STATE
;
3807 else /* default state */
3809 mii
->fState
|= MFS_ENABLED
;
3810 mii
->fMask
|= MIIM_STATE
;
3813 if(Flags
& MF_POPUP
)
3815 mii
->fType
|= MF_POPUP
;
3816 mii
->fMask
|= MIIM_SUBMENU
;
3817 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3821 mii
->fMask
|= MIIM_ID
;
3822 mii
->wID
= (UINT
)IDNewItem
;
3828 /* FUNCTIONS *****************************************************************/
3831 MenuIsStringItem(ULONG TypeData)
3833 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3841 AppendMenuA(HMENU hMenu
,
3843 UINT_PTR uIDNewItem
,
3846 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3855 AppendMenuW(HMENU hMenu
,
3857 UINT_PTR uIDNewItem
,
3860 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3869 CheckMenuItem(HMENU hmenu
,
3873 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3878 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3881 PROSMENUITEMINFO Items
= NULL
;
3882 UINT cChecked
, cUnchecked
;
3886 if(idFirst
> idLast
)
3889 ItemCount
= GetMenuItemCount(hMenu
);
3891 //mi.cbSize = sizeof(ROSMENUINFO);
3892 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3895 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3897 ERR("MenuGetAllRosMenuItemInfo failed\n");
3901 cChecked
= cUnchecked
= 0;
3903 for (i
= 0 ; i
< ItemCount
; i
++)
3906 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3907 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3909 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3911 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3914 if (uFlags
& MF_BYPOSITION
)
3916 if (i
< idFirst
|| i
> idLast
)
3931 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3934 if (Items
[i
].wID
== idCheck
)
3948 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
3951 Items
[i
].fType
|= MFT_RADIOCHECK
;
3952 Items
[i
].fState
|= MFS_CHECKED
;
3956 Items
[i
].fState
&= ~MFS_CHECKED
;
3959 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
3961 ERR("MenuSetRosMenuItemInfo failed\n");
3966 HeapFree(GetProcessHeap(), 0, Items
);
3968 *pChecked
+= cChecked
;
3969 *pUnchecked
+= cUnchecked
;
3971 if (cChecked
|| cUnchecked
)
3981 CheckMenuRadioItem(HMENU hmenu
,
3988 UINT cUnchecked
= 0;
3989 UINT cMenuChanged
= 0;
3991 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
3994 if (cMenuChanged
> 1)
4001 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4004 return (cChecked
!= 0);
4015 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4023 CreatePopupMenu(VOID
)
4026 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4034 DeleteMenu(HMENU hMenu
,
4038 return NtUserDeleteMenu(hMenu
, uPosition
, uFlags
);
4046 DestroyMenu(HMENU hMenu
)
4048 return NtUserDestroyMenu(hMenu
);
4056 DrawMenuBar(HWND hWnd
)
4058 return (BOOL
)NtUserCallHwndLock(hWnd
, HWNDLOCK_ROUTINE_DRAWMENUBAR
);
4066 EnableMenuItem(HMENU hMenu
,
4070 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4080 guii
.cbSize
= sizeof(GUITHREADINFO
);
4081 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4083 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4095 return NtUserGetMenu(hWnd
);
4103 GetMenuBarInfo(HWND hwnd
,
4108 return (BOOL
)NtUserGetMenuBarInfo(hwnd
, idObject
, idItem
, pmbi
);
4116 GetMenuCheckMarkDimensions(VOID
)
4118 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4119 GetSystemMetrics(SM_CYMENUCHECK
)));
4127 GetMenuDefaultItem(HMENU hMenu
,
4131 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4139 GetMenuInfo(HMENU hmenu
,
4145 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4148 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4149 mi
.cbSize
= sizeof(MENUINFO
);
4150 mi
.fMask
= lpcmi
->fMask
;
4152 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4154 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4163 GetMenuItemCount(HMENU Menu
)
4165 ROSMENUINFO MenuInfo
;
4167 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4175 GetMenuItemID(HMENU hMenu
,
4178 ROSMENUITEMINFO mii
;
4180 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4181 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4183 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4188 if (NULL
!= mii
.hSubMenu
)
4209 LPMENUITEMINFOA mii
)
4215 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4216 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4218 SetLastError(ERROR_INVALID_PARAMETER
);
4222 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4224 /* No text requested, just pass on */
4225 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4228 AnsiBuffer
= mii
->dwTypeData
;
4229 Count
= miiW
.cch
= mii
->cch
;
4230 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4231 miiW
.dwTypeData
= 0;
4235 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4236 miiW
.cch
* sizeof(WCHAR
));
4237 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4238 miiW
.dwTypeData
[0] = 0;
4241 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4243 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4247 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4249 if (!AnsiBuffer
|| !Count
)
4251 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4252 mii
->dwTypeData
= AnsiBuffer
;
4253 mii
->cch
= miiW
.cch
;
4257 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4261 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4265 if (Count
> miiW
.cch
)
4267 AnsiBuffer
[miiW
.cch
] = 0;
4269 mii
->cch
= mii
->cch
;
4277 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4278 mii
->dwTypeData
= AnsiBuffer
;
4292 LPMENUITEMINFOW mii
)
4298 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4299 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4301 SetLastError(ERROR_INVALID_PARAMETER
);
4305 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4307 /* No text requested, just pass on */
4308 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4311 String
= mii
->dwTypeData
;
4313 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4314 miiW
.dwTypeData
= 0;
4318 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4319 miiW
.cch
* sizeof(WCHAR
));
4320 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4321 miiW
.dwTypeData
[0] = 0;
4324 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4326 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4330 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4332 if (!String
|| !Count
)
4334 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4335 mii
->dwTypeData
= String
; // may not be zero.
4336 mii
->cch
= miiW
.cch
;
4340 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4342 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4345 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4346 mii
->dwTypeData
= String
;
4347 mii
->cch
= strlenW(String
);
4356 GetMenuItemRect(HWND hWnd
,
4361 return NtUserGetMenuItemRect( hWnd
, hMenu
, uItem
, lprcItem
);
4375 ROSMENUINFO MenuInfo
;
4376 ROSMENUITEMINFO mii
;
4377 memset( &mii
, 0, sizeof(mii
) );
4378 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4379 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4382 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4387 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4391 nSubItems
= MenuInfo
.MenuItemCount
;
4393 /* FIXME - ported from wine, does that work (0xff)? */
4394 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4395 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4397 return (UINT
)-1; /* Invalid submenu */
4400 /* FIXME - ported from wine, does that work? */
4401 return (mii
.fType
| mii
.fState
);
4421 memset( &mii
, 0, sizeof(mii
) );
4422 mii
.dwTypeData
= lpString
;
4423 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4424 mii
.fType
= MFT_STRING
;
4425 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4426 mii
.cch
= nMaxCount
;
4428 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4448 memset( &miiW
, 0, sizeof(miiW
) );
4449 miiW
.dwTypeData
= lpString
;
4450 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4451 miiW
.fType
= MFT_STRING
;
4452 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4453 miiW
.cch
= nMaxCount
;
4455 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4473 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4474 mi
.fMask
= MIIM_SUBMENU
;
4476 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4478 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4495 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4497 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4512 return NtUserHiliteMenuItem(hwnd
, hmenu
, uItemHilite
, uHilite
);
4526 UINT_PTR uIDNewItem
,
4530 memset( &mii
, 0, sizeof(mii
) );
4531 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4532 mii
.fMask
= MIIM_FTYPE
;
4534 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4537 (LPCWSTR
) lpNewItem
,
4540 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4554 LPCMENUITEMINFOA lpmii
)
4557 UNICODE_STRING MenuText
;
4559 BOOL CleanHeap
= FALSE
;
4562 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4563 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4565 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4567 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4569 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4572 /* copy the text string */
4573 if (((mi
.fMask
& MIIM_STRING
) ||
4574 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4575 && mi
.dwTypeData
!= NULL
)
4577 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4578 if (!NT_SUCCESS (Status
))
4580 SetLastError (RtlNtStatusToDosError(Status
));
4583 mi
.dwTypeData
= MenuText
.Buffer
;
4584 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4587 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4589 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4604 LPCMENUITEMINFOW lpmii
)
4607 UNICODE_STRING MenuText
;
4610 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4611 if a bad user passes bad data, we crash his process instead of the
4614 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4615 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4617 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4619 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4621 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4624 /* copy the text string */
4625 if (((mi
.fMask
& MIIM_STRING
) ||
4626 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4627 && mi
.dwTypeData
!= NULL
)
4629 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4630 mi
.dwTypeData
= MenuText
.Buffer
;
4631 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4633 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4648 UINT_PTR uIDNewItem
,
4652 memset( &mii
, 0, sizeof(mii
) );
4653 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4654 mii
.fMask
= MIIM_FTYPE
;
4656 MenuSetItemData( &mii
,
4662 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4674 ROSMENUINFO MenuInfo
;
4676 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4684 LoadMenuA(HINSTANCE hInstance
,
4687 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4688 if (Resource
== NULL
)
4692 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4700 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4702 return(LoadMenuIndirectW(lpMenuTemplate
));
4710 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4713 WORD version
, offset
;
4714 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4716 version
= GET_WORD(p
);
4721 case 0: /* standard format is version of 0 */
4722 offset
= GET_WORD(p
);
4723 p
+= sizeof(WORD
) + offset
;
4724 if (!(hMenu
= CreateMenu())) return 0;
4725 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4731 case 1: /* extended format is version of 1 */
4732 offset
= GET_WORD(p
);
4733 p
+= sizeof(WORD
) + offset
;
4734 if (!(hMenu
= CreateMenu())) return 0;
4735 if (!MENUEX_ParseResource(p
, hMenu
))
4737 DestroyMenu( hMenu
);
4742 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4752 LoadMenuW(HINSTANCE hInstance
,
4755 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4756 if (Resource
== NULL
)
4760 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4774 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4787 UINT_PTR uIDNewItem
,
4791 ROSMENUITEMINFO rmii
;
4793 memset( &mii
, 0, sizeof(mii
) );
4794 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4795 mii
.fMask
= MIIM_FTYPE
;
4797 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4801 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4803 MenuInitRosMenuItemInfo( &rmii
);
4805 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4807 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4808 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4810 MenuCleanupRosMenuItemInfo( &rmii
);
4812 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4815 (LPCWSTR
) lpNewItem
,
4818 return SetMenuItemInfoA( hMnu
,
4820 (BOOL
)(MF_BYPOSITION
& uFlags
),
4834 UINT_PTR uIDNewItem
,
4838 ROSMENUITEMINFO rmii
;
4840 memset ( &mii
, 0, sizeof(mii
) );
4841 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4842 mii
.fMask
= MIIM_FTYPE
;
4844 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4846 mi
.Height
= 0; // Force size recalculation.
4848 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4850 MenuInitRosMenuItemInfo( &rmii
);
4852 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4854 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4855 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4857 MenuCleanupRosMenuItemInfo( &rmii
);
4859 /* Init new data for this menu item */
4860 MenuSetItemData( &mii
,
4866 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4867 return SetMenuItemInfoW( hMnu
,
4869 (BOOL
)(MF_BYPOSITION
& uFlags
),
4884 return NtUserRemoveMenu(hMenu
, uPosition
, uFlags
);
4895 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4909 return NtUserSetMenuDefaultItem(hMenu
, uItem
, fByPos
);
4924 if(lpcmi
->cbSize
!= sizeof(MENUINFO
))
4927 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4928 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4941 HBITMAP hBitmapUnchecked
,
4942 HBITMAP hBitmapChecked
)
4944 ROSMENUITEMINFO uItem
;
4945 memset ( &uItem
, 0, sizeof(uItem
) );
4946 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4948 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4949 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4951 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4953 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4955 else /* Install new bitmaps */
4957 uItem
.hbmpChecked
= hBitmapChecked
;
4958 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4959 uItem
.fState
|= MF_USECHECKBITMAPS
;
4961 return NtUserMenuItemInfo(hMenu
, uPosition
,
4962 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4975 LPCMENUITEMINFOA lpmii
)
4977 MENUITEMINFOW MenuItemInfoW
;
4978 UNICODE_STRING UnicodeString
;
4980 ULONG Result
= FALSE
;
4982 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4984 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4986 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4987 MenuItemInfoW
.hbmpItem
= NULL
;
4990 * MIIM_STRING == good
4991 * MIIM_TYPE & MFT_STRING == good
4992 * MIIM_STRING & MFT_STRING == good
4993 * MIIM_STRING & MFT_OWNERSRAW == good
4995 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4996 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4997 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4998 && MenuItemInfoW
.dwTypeData
!= NULL
)
5000 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5001 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5002 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5003 if (!NT_SUCCESS (Status
))
5005 SetLastError (RtlNtStatusToDosError(Status
));
5008 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5009 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5013 UnicodeString
.Buffer
= NULL
;
5016 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5017 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5019 if (UnicodeString
.Buffer
!= NULL
)
5021 RtlFreeUnicodeString(&UnicodeString
);
5037 LPCMENUITEMINFOW lpmii
)
5039 MENUITEMINFOW MenuItemInfoW
;
5042 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5044 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5046 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5047 MenuItemInfoW
.hbmpItem
= NULL
;
5050 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5051 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5052 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5053 && MenuItemInfoW
.dwTypeData
!= NULL
)
5055 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5057 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5058 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5074 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5079 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5082 return NtUserSetSystemMenu(hwnd
, hMenu
);
5102 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
5104 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
5105 if (0 == (Flags
& TPM_NONOTIFY
))
5107 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5110 if (MenuShowPopup(Wnd
, Menu
, 0, x
, y
, 0, 0 ))
5112 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5114 MenuExitTracking(Wnd
);
5133 /* Not fully implemented */
5134 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5135 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5139 // Example for the Win32/User32 rewrite.
5140 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5154 return NtUserTrackPopupMenuEx( Menu
,
5159 NULL
); // LPTPMPARAMS is null
5168 SetMenuContextHelpId(HMENU hmenu
,
5169 DWORD dwContextHelpId
)
5171 return NtUserSetMenuContextHelpId(hmenu
, dwContextHelpId
);
5180 GetMenuContextHelpId(HMENU hmenu
)
5183 mi
.cbSize
= sizeof(ROSMENUINFO
);
5184 mi
.fMask
= MIM_HELPID
;
5186 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5188 return mi
.dwContextHelpID
;
5233 LPCWSTR lpszNewItem
,
5238 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5239 for MF_DELETE. We should check the parameters for all others
5240 MF_* actions also (anybody got a doc on ChangeMenu?).
5243 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5246 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5249 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5252 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5255 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5256 flags
&~ MF_REMOVE
);
5258 default : /* MF_INSERT */
5259 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5276 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5277 for MF_DELETE. We should check the parameters for all others
5278 MF_* actions also (anybody got a doc on ChangeMenu?).
5281 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5284 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5287 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5290 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5293 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5294 flags
&~ MF_REMOVE
);
5296 default : /* MF_INSERT */
5297 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);