3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS user32.dll
5 * FILE: user32/windows/menu.c
8 * PROGRAMMERS: Casper S. Hornstrup
12 /* INCLUDES ******************************************************************/
16 #include <wine/debug.h>
17 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
19 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
21 /* internal popup menu window messages */
22 #define MM_SETMENUHANDLE (WM_USER + 0)
23 #define MM_GETMENUHANDLE (WM_USER + 1)
25 /* Internal MenuTrackMenu() flags */
26 #define TPM_INTERNAL 0xF0000000
27 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
28 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
29 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
31 /* TYPES *********************************************************************/
33 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
35 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
36 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
37 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
39 #define IS_SYSTEM_MENU(MenuInfo) \
40 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
42 #define IS_SYSTEM_POPUP(MenuInfo) \
43 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
45 #define IS_MAGIC_ITEM(Bmp) ((int) Bmp <12)
46 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
48 #define MENU_ITEM_HBMP_SPACE (5)
49 #define MENU_BAR_ITEMS_SPACE (12)
50 #define SEPARATOR_HEIGHT (5)
51 #define MENU_TAB_SPACE (8)
56 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
57 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
58 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
59 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
61 /* internal flags for menu tracking */
63 #define TF_ENDMENU 0x0001
64 #define TF_SUSPENDPOPUP 0x0002
65 #define TF_SKIPREMOVE 0x0004
70 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
71 HMENU TopMenu
; /* initial menu */
72 HWND OwnerWnd
; /* where notifications are sent */
76 static LRESULT WINAPI
PopupMenuWndProcW(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
78 /*********************************************************************
79 * PopupMenu class descriptor
81 const struct builtin_class_descr POPUPMENU_builtin_class
=
83 POPUPMENU_CLASS_ATOMW
, /* name */
84 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
85 (WNDPROC
) NULL
, /* FIXME - procA */
86 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
87 sizeof(MENUINFO
*), /* extra */
88 (LPCWSTR
) IDC_ARROW
, /* cursor */
89 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
93 /* INTERNAL FUNCTIONS ********************************************************/
95 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
96 * Of course I didnt copy the ASM code because we want this to be portable
97 * and it needs to go away.
101 #define GET_WORD(ptr) (*(WORD *)(ptr))
104 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
107 HFONT hMenuFont
= NULL
;
108 HFONT hMenuFontBold
= NULL
;
110 /* Flag set by EndMenu() to force an exit from menu tracking */
111 static BOOL fEndMenu
= FALSE
;
113 /* Use global popup window because there's no way 2 menus can
114 * be tracked at the same time. */
115 static HWND TopPopup
;
117 /* Dimension of the menu bitmaps */
118 static HBITMAP BmpSysMenu
= NULL
;
120 static SIZE MenuCharSize
;
122 /***********************************************************************
125 * Get full information about menu
128 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
130 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
131 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
133 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
136 /***********************************************************************
139 * Set full information about menu
142 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
144 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
145 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
147 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
150 /***********************************************************************
151 * MenuInitRosMenuItemInfo
153 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
156 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
158 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
159 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
162 /***********************************************************************
163 * MenuGetRosMenuItemInfo
165 * Get full information about a menu item
168 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
170 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
172 if (ItemInfo
->dwTypeData
!= NULL
)
174 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
178 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
179 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
180 ItemInfo
->dwTypeData
= NULL
;
182 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
188 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
191 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
192 ItemInfo
->cch
* sizeof(WCHAR
));
193 if (NULL
== ItemInfo
->dwTypeData
)
198 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
203 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
205 ItemInfo
->fMask
= Save_Mask
;
209 /***********************************************************************
210 * MenuSetRosMenuItemInfo
212 * Set selected information about a menu item, need to set the mask bits.
215 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
219 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
220 ItemInfo
->dwTypeData
!= NULL
)
222 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
224 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
229 /***********************************************************************
230 * MenuCleanupRosMenuItemInfo
232 * Cleanup after use of MenuGet/SetRosMenuItemInfo
235 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
237 if (ItemInfo
->dwTypeData
!= NULL
)
239 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
240 ItemInfo
->dwTypeData
= NULL
;
244 /***********************************************************************
245 * MenuGetAllRosMenuItemInfo
247 * Get full information about all menu items
250 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
254 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
255 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
259 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
260 if (NULL
== *ItemInfo
)
265 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
268 /***********************************************************************
269 * MenuCleanupAllRosMenuItemInfo
271 * Cleanup after use of MenuGetAllRosMenuItemInfo
274 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
276 HeapFree(GetProcessHeap(), 0, ItemInfo
);
280 /***********************************************************************
283 * Load the arrow bitmap. We can't do this from MenuInit since user32
284 * can also be used (and thus initialized) from text-mode.
287 MenuLoadBitmaps(VOID
)
289 /* Load system buttons bitmaps */
290 if (NULL
== BmpSysMenu
)
292 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
296 /***********************************************************************
297 * MenuGetBitmapItemSize
299 * Get the size of a bitmap item.
302 MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*Size
, HWND WndOwner
)
305 HBITMAP Bmp
= lpitem
->hbmpItem
;
307 Size
->cx
= Size
->cy
= 0;
309 /* check if there is a magic menu item associated with this item */
310 if (0 != Bmp
&& IS_MAGIC_ITEM((INT
)(Bmp
)))
312 switch((INT_PTR
) Bmp
)
314 case (INT_PTR
)HBMMENU_CALLBACK
:
316 MEASUREITEMSTRUCT measItem
;
317 measItem
.CtlType
= ODT_MENU
;
319 measItem
.itemID
= lpitem
->wID
;
320 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
321 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
322 measItem
.itemData
= lpitem
->dwItemData
;
323 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
324 Size
->cx
= measItem
.itemWidth
;
325 Size
->cy
= measItem
.itemHeight
;
330 case (INT_PTR
) HBMMENU_SYSTEM
:
331 if (0 != lpitem
->dwItemData
)
333 Bmp
= (HBITMAP
) lpitem
->dwItemData
;
337 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
338 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
339 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
340 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
341 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
342 /* FIXME: Why we need to subtract these magic values? */
343 /* to make them smaller than the menu bar? */
344 Size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
345 Size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
347 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
348 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
349 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
350 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
352 FIXME("Magic menu bitmap not implemented\n");
357 if (GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
359 Size
->cx
= Bm
.bmWidth
;
360 Size
->cy
= Bm
.bmHeight
;
364 /***********************************************************************
367 * Draw a bitmap item.
370 MenuDrawBitmapItem(HDC Dc
, PROSMENUITEMINFO Item
, const RECT
*Rect
,
371 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
377 int w
= Rect
->right
- Rect
->left
;
378 int h
= Rect
->bottom
- Rect
->top
;
381 HBITMAP hbmpToDraw
= (HBITMAP
) Item
->hbmpItem
;
384 /* Check if there is a magic menu item associated with this item */
385 if (IS_MAGIC_ITEM(hbmpToDraw
))
391 switch ((INT_PTR
)hbmpToDraw
)
393 case (INT_PTR
) HBMMENU_SYSTEM
:
394 if (NULL
!= Item
->dwTypeData
)
396 Bmp
= (HBITMAP
)Item
->dwTypeData
;
397 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
404 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
406 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
410 /* only use right half of the bitmap */
411 BmpXoffset
= Bm
.bmWidth
/ 2;
412 Bm
.bmWidth
-= BmpXoffset
;
415 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
416 Flags
= DFCS_CAPTIONRESTORE
;
418 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
420 Flags
= DFCS_CAPTIONMIN
;
422 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
424 Flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
426 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
427 Flags
= DFCS_CAPTIONCLOSE
;
429 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
430 Flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
432 case (INT_PTR
) HBMMENU_CALLBACK
:
434 DRAWITEMSTRUCT drawItem
;
436 drawItem
.CtlType
= ODT_MENU
;
438 drawItem
.itemID
= Item
->wID
;
439 drawItem
.itemAction
= odaction
;
440 drawItem
.itemState
= (Item
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
441 drawItem
.itemState
|= (Item
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
442 drawItem
.itemState
|= (Item
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
443 drawItem
.itemState
|= (Item
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
444 drawItem
.itemState
|= (Item
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
445 drawItem
.hwndItem
= (HWND
)hmenu
;
447 drawItem
.rcItem
= *Rect
;
448 drawItem
.itemData
= Item
->dwItemData
;
449 /* some applications make this assumption on the DC's origin */
450 SetViewportOrgEx( Dc
, Item
->Rect
.left
, Item
->Rect
.top
, &origorg
);
451 OffsetRect( &drawItem
.rcItem
, - Item
->Rect
.left
, - Item
->Rect
.top
);
452 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
453 SetViewportOrgEx( Dc
, origorg
.x
, origorg
.y
, NULL
);
458 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
459 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
460 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
461 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
463 FIXME("Magic menu bitmap not implemented\n");
466 InflateRect(&r
, -1, -1);
467 if (0 != (Item
->fState
& MF_HILITE
))
469 Flags
|= DFCS_PUSHED
;
471 DrawFrameControl(Dc
, &r
, DFC_CAPTION
, Flags
);
475 if (NULL
== Bmp
|| ! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
481 DcMem
= CreateCompatibleDC(Dc
);
482 SelectObject(DcMem
, Bmp
);
484 /* handle fontsize > bitmap_height */
485 Top
= (Bm
.bmHeight
< h
) ? Rect
->top
+ (h
- Bm
.bmHeight
) / 2 : Rect
->top
;
487 Rop
= ((Item
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmpToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
488 if ((Item
->fState
& MF_HILITE
) && Item
->hbmpItem
)
490 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
492 BitBlt(Dc
, Left
, Top
, w
, h
, DcMem
, BmpXoffset
, 0, Rop
);
496 /***********************************************************************
499 * Draw a single menu item.
502 MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC Dc
,
503 PROSMENUITEMINFO Item
, UINT Height
, BOOL MenuBar
, UINT Action
)
507 BOOL flat_menu
= FALSE
;
509 PWINDOW Wnd
= ValidateHwnd(hWnd
);
514 if (0 != (Item
->fType
& MF_SYSMENU
))
516 if ( (Wnd
->Style
& WS_MINIMIZE
))
518 UserGetInsideRectNC(Wnd
, &Rect
);
519 UserDrawSysMenuButton(hWnd
, Dc
, &Rect
,
520 Item
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
525 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
526 bkgnd
= (MenuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
530 if (0 != (Item
->fState
& MF_HILITE
))
532 if (MenuBar
&& !flat_menu
)
534 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
535 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
539 if (0 != (Item
->fState
& MF_GRAYED
))
541 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
545 SetTextColor(Dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
547 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
552 if (0 != (Item
->fState
& MF_GRAYED
))
554 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
558 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
560 SetBkColor(Dc
, GetSysColor(bkgnd
));
565 if (Item
->fType
& MF_OWNERDRAW
)
568 ** Experimentation under Windows reveals that an owner-drawn
569 ** menu is given the rectangle which includes the space it requested
570 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
571 ** and a popup-menu arrow. This is the value of lpitem->rect.
572 ** Windows will leave all drawing to the application except for
573 ** the popup-menu arrow. Windows always draws that itself, after
574 ** the menu owner has finished drawing.
578 dis
.CtlType
= ODT_MENU
;
580 dis
.itemID
= Item
->wID
;
581 dis
.itemData
= (DWORD
)Item
->dwItemData
;
583 if (0 != (Item
->fState
& MF_CHECKED
))
585 dis
.itemState
|= ODS_CHECKED
;
587 if (0 != (Item
->fState
& MF_GRAYED
))
589 dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
591 if (0 != (Item
->fState
& MF_HILITE
))
593 dis
.itemState
|= ODS_SELECTED
;
595 dis
.itemAction
= Action
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
596 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
599 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
600 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
601 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
602 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
604 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
605 /* Draw the popup-menu arrow */
606 if (0 != (Item
->fType
& MF_POPUP
))
609 CopyRect(&rectTemp
, &Rect
);
610 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
611 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
616 TRACE("rect={%ld,%ld,%ld,%ld}\n", Item
->Rect
.left
, Item
->Rect
.top
,
617 Item
->Rect
.right
, Item
->Rect
.bottom
);
619 if (MenuBar
&& 0 != (Item
->fType
& MF_SEPARATOR
))
624 if (Item
->fState
& MF_HILITE
)
628 InflateRect (&Rect
, -1, -1);
629 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
630 InflateRect (&Rect
, 1, 1);
631 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
637 DrawEdge(Dc
, &Rect
, BDR_SUNKENOUTER
, BF_RECT
);
641 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
647 FillRect(Dc
, &Rect
, GetSysColorBrush(bkgnd
));
650 SetBkMode(Dc
, TRANSPARENT
);
652 /* vertical separator */
653 if (! MenuBar
&& 0 != (Item
->fType
& MF_MENUBARBREAK
))
659 rc
.bottom
= Height
- 3;
662 oldPen
= SelectObject( Dc
, GetSysColorPen(COLOR_BTNSHADOW
) );
663 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
664 LineTo( Dc
, rc
.left
, rc
.bottom
);
665 SelectObject( Dc
, oldPen
);
668 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
671 /* horizontal separator */
672 if (0 != (Item
->fType
& MF_SEPARATOR
))
678 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
681 oldPen
= SelectObject( Dc
, GetSysColorPen(COLOR_BTNSHADOW
) );
682 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
683 LineTo( Dc
, rc
.right
, rc
.top
);
684 SelectObject( Dc
, oldPen
);
687 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_TOP
);
692 /* helper lines for debugging */
693 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
694 FrameRect(Dc
, &Rect
, GetStockObject(BLACK_BRUSH
));
695 SelectObject(Dc
, GetSysColorPen(COLOR_WINDOWFRAME
));
696 MoveToEx(Dc
, Rect
.left
, (Rect
.top
+ Rect
.bottom
) / 2, NULL
);
697 LineTo(Dc
, Rect
.right
, (Rect
.top
+ Rect
.bottom
) / 2);
702 INT y
= Rect
.top
+ Rect
.bottom
;
704 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
705 UINT CheckBitmapHeight
= GetSystemMetrics(SM_CYMENUCHECK
);
707 /* Draw the check mark
710 * Custom checkmark bitmaps are monochrome but not always 1bpp.
712 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
714 HBITMAP bm
= 0 != (Item
->fState
& MF_CHECKED
) ? Item
->hbmpChecked
: Item
->hbmpUnchecked
;
715 if (NULL
!= bm
) /* we have a custom bitmap */
717 HDC DcMem
= CreateCompatibleDC(Dc
);
718 SelectObject(DcMem
, bm
);
719 BitBlt(Dc
, Rc
.left
, (y
- CheckBitmapHeight
) / 2,
720 CheckBitmapWidth
, CheckBitmapHeight
,
721 DcMem
, 0, 0, SRCCOPY
);
725 else if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
728 CopyRect(&rectTemp
, &Rect
);
729 rectTemp
.right
= rectTemp
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
730 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
,
731 0 != (Item
->fType
& MFT_RADIOCHECK
) ?
732 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
736 if ((Item
->hbmpItem
)&& !( checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
738 MenuDrawBitmapItem(Dc
, Item
, &Rect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
740 /* Draw the popup-menu arrow */
741 if (0 != (Item
->fType
& MF_POPUP
))
744 CopyRect(&rectTemp
, &Rect
);
745 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
746 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
749 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
750 Rect
.left
+= CheckBitmapWidth
;
751 Rect
.right
-= CheckBitmapWidth
;
753 else if (Item
->hbmpItem
) /* Draw the bitmap */
755 MenuDrawBitmapItem(Dc
, Item
, &Rect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
758 /* No bitmap - process text if present */
762 HFONT FontOld
= NULL
;
764 UINT uFormat
= MenuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
765 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
767 if( !(MenuInfo
->dwStyle
& MNS_CHECKORBMP
))
768 Rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
770 if (0 != (Item
->fState
& MFS_DEFAULT
))
772 FontOld
= SelectObject(Dc
, hMenuFontBold
);
777 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
778 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
780 if (Item
->hbmpItem
== HBMMENU_CALLBACK
|| MenuInfo
->maxBmpSize
.cx
!= 0 )
782 Rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
783 Rect
.right
-= MenuInfo
->maxBmpSize
.cx
;
786 Text
= (PWCHAR
) Item
->dwTypeData
;
789 for (i
= 0; L
'\0' != Text
[i
]; i
++)
791 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
798 if (0 != (Item
->fState
& MF_GRAYED
))
800 if (0 == (Item
->fState
& MF_HILITE
))
802 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
803 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
804 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
805 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
807 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
810 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
812 /* paint the shortcut text */
813 if (! MenuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
815 if (L
'\t' == Text
[i
])
817 Rect
.left
= Item
->XTab
;
818 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
822 Rect
.right
= Item
->XTab
;
823 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
826 if (0 != (Item
->fState
& MF_GRAYED
))
828 if (0 == (Item
->fState
& MF_HILITE
))
830 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
831 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
832 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
833 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
835 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
837 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
842 SelectObject(Dc
, FontOld
);
847 /***********************************************************************
850 * Paint a popup menu.
853 MenuDrawPopupMenu(HWND Wnd
, HDC Dc
, HMENU Menu
)
855 HBRUSH PrevBrush
= NULL
;
858 ROSMENUINFO MenuInfo
;
859 ROSMENUITEMINFO ItemInfo
;
862 TRACE("wnd=%x dc=%x menu=%x\n", Wnd
, Dc
, Menu
);
864 GetClientRect(Wnd
, &Rect
);
866 if (NULL
!= (PrevBrush
= SelectObject(Dc
, GetSysColorBrush(COLOR_MENU
)))
867 && NULL
!= SelectObject(Dc
, hMenuFont
))
869 Rectangle(Dc
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
871 PrevPen
= SelectObject(Dc
, GetStockObject(NULL_PEN
));
874 BOOL flat_menu
= FALSE
;
876 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
878 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
880 DrawEdge(Dc
, &Rect
, EDGE_RAISED
, BF_RECT
);
882 /* draw menu items */
884 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 != MenuInfo
.MenuItemCount
)
886 MenuInitRosMenuItemInfo(&ItemInfo
);
888 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
890 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
892 MenuDrawMenuItem(Wnd
, &MenuInfo
, MenuInfo
.WndOwner
, Dc
, &ItemInfo
,
893 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
897 MenuCleanupRosMenuItemInfo(&ItemInfo
);
902 SelectObject(Dc
, PrevBrush
);
907 static LRESULT WINAPI
908 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
910 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
916 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
917 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
921 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
922 return MA_NOACTIVATE
;
927 BeginPaint(Wnd
, &ps
);
928 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
937 /* zero out global pointer in case resident popup window was destroyed. */
947 if (0 == GetWindowLongPtrW(Wnd
, 0))
949 OutputDebugStringA("no menu to display\n");
954 SetWindowLongPtrW(Wnd
, 0, 0);
958 case MM_SETMENUHANDLE
:
959 SetWindowLongPtrW(Wnd
, 0, wParam
);
962 case MM_GETMENUHANDLE
:
963 return GetWindowLongPtrW(Wnd
, 0);
966 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
972 /**********************************************************************
973 * MENUEX_ParseResource
975 * Parse an extended menu resource and add items to the menu.
976 * Return a pointer to the end of the resource.
978 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
980 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
988 mii
.cbSize
= sizeof(mii
);
989 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
990 mii
.fType
= GET_DWORD(res
);
991 res
+= sizeof(DWORD
);
992 mii
.fState
= GET_DWORD(res
);
993 res
+= sizeof(DWORD
);
994 mii
.wID
= GET_DWORD(res
);
995 res
+= sizeof(DWORD
);
996 resinfo
= GET_WORD(res
);
998 /* Align the text on a word boundary. */
999 res
+= (~((int)res
- 1)) & 1;
1000 mii
.dwTypeData
= (LPWSTR
) res
;
1001 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1002 /* Align the following fields on a dword boundary. */
1003 res
+= (~((int)res
- 1)) & 3;
1005 if (resinfo
& 1) /* Pop-up? */
1007 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1008 res
+= sizeof(DWORD
);
1009 mii
.hSubMenu
= CreatePopupMenu();
1012 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1014 DestroyMenu(mii
.hSubMenu
);
1017 mii
.fMask
|= MIIM_SUBMENU
;
1018 mii
.fType
|= MF_POPUP
;
1019 mii
.wID
= (UINT
) mii
.hSubMenu
;
1021 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1023 mii
.fType
|= MF_SEPARATOR
;
1025 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1027 while (!(resinfo
& MF_END
));
1032 /**********************************************************************
1033 * MENU_ParseResource
1035 * Parse a standard menu resource and add items to the menu.
1036 * Return a pointer to the end of the resource.
1038 * NOTE: flags is equivalent to the mtOption field
1040 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1049 flags
= GET_WORD(res
);
1051 /* remove MF_END flag before passing it to AppendMenu()! */
1052 end
= (flags
& MF_END
);
1053 if(end
) flags
^= MF_END
;
1055 res
+= sizeof(WORD
);
1056 if(!(flags
& MF_POPUP
))
1059 res
+= sizeof(WORD
);
1063 res
+= strlen(str
) + 1;
1065 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1066 if (flags
& MF_POPUP
)
1068 hSubMenu
= CreatePopupMenu();
1069 if(!hSubMenu
) return NULL
;
1070 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1073 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1075 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1077 else /* Not a popup */
1080 flags
= MF_SEPARATOR
;
1082 if (flags
& MF_SEPARATOR
)
1084 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1085 flags
|= MF_GRAYED
| MF_DISABLED
;
1089 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1091 AppendMenuW(hMenu
, flags
, id
,
1092 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1101 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1104 Result
= (LRESULT
)LoadMenuW(User32Instance
, L
"SYSMENU");
1105 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1112 NONCLIENTMETRICSW ncm
;
1114 /* get the menu font */
1115 if(!hMenuFont
|| !hMenuFontBold
)
1117 ncm
.cbSize
= sizeof(ncm
);
1118 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1120 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1124 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1125 if(hMenuFont
== NULL
)
1127 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1131 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1132 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1133 if(hMenuFontBold
== NULL
)
1135 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1136 DeleteObject(hMenuFont
);
1151 DeleteObject(hMenuFont
);
1157 DeleteObject(hMenuFontBold
);
1158 hMenuFontBold
= NULL
;
1164 /***********************************************************************
1167 * Calculate the size of the menu item and store it in ItemInfo->rect.
1169 static void FASTCALL
1170 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, PROSMENUINFO MenuInfo
, HWND WndOwner
,
1171 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1175 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1177 TRACE("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1179 MenuCharSize
.cx
= GdiGetCharDimensions( Dc
, NULL
, &MenuCharSize
.cy
);
1181 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1183 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1186 ** Experimentation under Windows reveals that an owner-drawn
1187 ** menu is expected to return the size of the content part of
1188 ** the menu item, not including the checkmark nor the submenu
1189 ** arrow. Windows adds those values itself and returns the
1190 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1192 MEASUREITEMSTRUCT mis
;
1193 mis
.CtlType
= ODT_MENU
;
1195 mis
.itemID
= ItemInfo
->wID
;
1196 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1197 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1199 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1200 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1201 * width of a menufont character to the width of an owner-drawn menu.
1203 ItemInfo
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1207 /* under at least win95 you seem to be given a standard
1208 height for the menu and the height value is ignored */
1209 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1213 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1216 TRACE("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1220 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1222 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1224 ItemInfo
->Rect
.right
+= CheckBitmapWidth
+ MenuCharSize
.cx
;
1230 if (ItemInfo
->hbmpItem
)
1234 if (!MenuBar
) /* hbmpItem */
1236 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1237 /* Keep the size of the bitmap in callback mode to be able
1238 * to draw it correctly */
1239 ItemInfo
->Rect
.right
= ItemInfo
->Rect
.left
+ Size
.cx
;
1240 if (MenuInfo
->maxBmpSize
.cx
< abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
||
1241 MenuInfo
->maxBmpSize
.cy
< abs(Size
.cy
))
1243 MenuInfo
->maxBmpSize
.cx
= abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
;
1244 MenuInfo
->maxBmpSize
.cy
= abs(Size
.cy
);
1246 MenuSetRosMenuInfo(MenuInfo
);
1247 ItemInfo
->Rect
.right
+= Size
.cx
+ 2;
1248 itemheight
= Size
.cy
+ 2;
1250 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1251 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1252 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1253 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1254 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1256 else /* hbmpItem & MenuBar */
1258 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1259 ItemInfo
->Rect
.right
+= Size
.cx
;
1260 if( ItemInfo
->Text
) ItemInfo
->Rect
.right
+= 2;
1261 itemheight
= Size
.cy
;
1263 /* Special case: Minimize button doesn't have a space behind it. */
1264 if (ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1265 ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1266 ItemInfo
->Rect
.right
-= 1;
1271 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1272 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1273 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1274 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1275 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1278 /* it must be a text item - unless it's the system menu */
1279 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && ItemInfo
->Text
)
1281 HFONT hfontOld
= NULL
;
1282 RECT rc
= ItemInfo
->Rect
;
1283 LONG txtheight
, txtwidth
;
1285 if ( ItemInfo
->fState
& MFS_DEFAULT
)
1287 hfontOld
= SelectObject( Dc
, hMenuFontBold
);
1291 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1292 DT_SINGLELINE
|DT_CALCRECT
);
1293 ItemInfo
->Rect
.right
+= rc
.right
- rc
.left
;
1294 itemheight
= max( max( itemheight
, txtheight
),
1295 GetSystemMetrics( SM_CYMENU
) - 1);
1296 ItemInfo
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1300 if ((p
= strchrW( ItemInfo
->dwTypeData
, '\t' )) != NULL
)
1304 int n
= (int)( p
- ItemInfo
->dwTypeData
);
1305 /* Item contains a tab (only meaningful in popup menus) */
1306 /* get text size before the tab */
1307 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, n
, &rc
,
1308 DT_SINGLELINE
|DT_CALCRECT
);
1309 txtwidth
= rc
.right
- rc
.left
;
1310 p
+= 1; /* advance past the Tab */
1311 /* get text size after the tab */
1312 tmpheight
= DrawTextW( Dc
, p
, -1, &tmprc
, DT_SINGLELINE
|DT_CALCRECT
);
1313 ItemInfo
->XTab
+= txtwidth
;
1314 txtheight
= max( txtheight
, tmpheight
);
1315 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1316 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1320 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1321 DT_SINGLELINE
|DT_CALCRECT
);
1322 txtwidth
= rc
.right
- rc
.left
;
1323 ItemInfo
->XTab
+= txtwidth
;
1325 ItemInfo
->Rect
.right
+= 2 + txtwidth
;
1326 itemheight
= max( itemheight
, max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1328 if (hfontOld
) SelectObject (Dc
, hfontOld
);
1332 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1334 ItemInfo
->Rect
.bottom
+= itemheight
;
1335 TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1338 /***********************************************************************
1339 * MenuPopupMenuCalcSize
1341 * Calculate the size of a popup menu.
1343 static void FASTCALL
1344 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1346 ROSMENUITEMINFO ItemInfo
;
1349 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1351 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1352 if (0 == MenuInfo
->MenuItemCount
)
1354 MenuSetRosMenuInfo(MenuInfo
);
1359 SelectObject(Dc
, hMenuFont
);
1364 MenuInfo
->maxBmpSize
.cx
= 0;
1365 MenuInfo
->maxBmpSize
.cy
= 0;
1367 MenuInitRosMenuItemInfo(&ItemInfo
);
1368 while (Start
< MenuInfo
->MenuItemCount
)
1373 MaxTab
= MaxTabWidth
= 0;
1375 /* Parse items until column break or end of menu */
1376 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1378 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1380 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1381 MenuSetRosMenuInfo(MenuInfo
);
1385 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1389 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1390 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1392 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1393 MenuSetRosMenuInfo(MenuInfo
);
1396 // Not sure here,, The patch from wine removes this.
1397 // if (0 != (ItemInfo.fType & MF_MENUBARBREAK))
1401 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1402 OrgY
= ItemInfo
.Rect
.bottom
;
1403 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1405 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1406 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1410 /* Finish the column (set all items to the largest width found) */
1411 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1414 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1416 ItemInfo
.Rect
.right
= MaxX
;
1417 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1419 ItemInfo
.XTab
= MaxTab
;
1421 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1425 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1428 MenuInfo
->Width
= MaxX
;
1430 /* space for 3d border */
1431 MenuInfo
->Height
+= 2;
1432 MenuInfo
->Width
+= 2;
1434 ReleaseDC(NULL
, Dc
);
1435 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1436 MenuSetRosMenuInfo(MenuInfo
);
1439 /***********************************************************************
1440 * MenuMenuBarCalcSize
1442 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1443 * height is off by 1 pixel which causes lengthy window relocations when
1444 * active document window is maximized/restored.
1446 * Calculate the size of the menu bar.
1448 static void FASTCALL
1449 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1451 ROSMENUITEMINFO ItemInfo
;
1452 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1454 if (NULL
== Rect
|| NULL
== MenuInfo
)
1458 if (0 == MenuInfo
->MenuItemCount
)
1463 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1464 Rect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1465 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1466 MenuInfo
->Height
= 0;
1467 MaxY
= Rect
->top
+ 1;
1471 MenuInfo
->maxBmpSize
.cx
= 0;
1472 MenuInfo
->maxBmpSize
.cy
= 0;
1474 MenuInitRosMenuItemInfo(&ItemInfo
);
1475 while (Start
< MenuInfo
->MenuItemCount
)
1477 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1479 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1485 /* Parse items until line break or end of menu */
1486 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1488 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1493 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1498 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1499 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1500 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1502 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1506 if (ItemInfo
.Rect
.right
> Rect
->right
)
1514 ItemInfo
.Rect
.right
= Rect
->right
;
1517 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1518 OrgX
= ItemInfo
.Rect
.right
;
1519 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1521 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1523 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1529 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1530 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1532 /* Finish the line (set all items to the largest height found) */
1535 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1537 ItemInfo
.Rect
.bottom
= MaxY
;
1538 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1543 Start
= i
; /* This works! */
1547 Rect
->bottom
= MaxY
;
1548 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1549 MenuSetRosMenuInfo(MenuInfo
);
1553 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1554 /* the last item (if several lines, only move the last line) */
1555 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1557 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1560 OrgY
= ItemInfo
.Rect
.top
;
1562 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1568 if (ItemInfo
.Rect
.top
!= OrgY
)
1570 break; /* Other line */
1572 if (OrgX
<= ItemInfo
.Rect
.right
)
1574 break; /* Too far right already */
1576 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1577 ItemInfo
.Rect
.right
= OrgX
;
1578 OrgX
= ItemInfo
.Rect
.left
;
1579 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1580 if (HelpPos
+ 1 <= i
&&
1581 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1583 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1589 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1592 /***********************************************************************
1593 * DrawMenuBarTemp (USER32.@)
1597 * called by W98SE desk.cpl Control Panel Applet
1599 * Not 100% sure about the param names, but close.
1604 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1606 ROSMENUINFO MenuInfo
;
1607 ROSMENUITEMINFO ItemInfo
;
1609 HFONT FontOld
= NULL
;
1610 BOOL flat_menu
= FALSE
;
1612 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1616 Menu
= GetMenu(Wnd
);
1624 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1626 return GetSystemMetrics(SM_CYMENU
);
1629 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1631 FontOld
= SelectObject(DC
, Font
);
1633 if (0 == MenuInfo
.Height
)
1635 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1638 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1640 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
1642 SelectObject(DC
, GetSysColorPen(COLOR_3DFACE
));
1643 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1644 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1646 if (0 == MenuInfo
.MenuItemCount
)
1648 SelectObject(DC
, FontOld
);
1649 return GetSystemMetrics(SM_CYMENU
);
1652 MenuInitRosMenuItemInfo(&ItemInfo
);
1653 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1655 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1657 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1658 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1661 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1663 SelectObject(DC
, FontOld
);
1665 return MenuInfo
.Height
;
1669 /***********************************************************************
1672 * Paint a menu bar. Returns the height of the menu bar.
1673 * called from [windows/nonclient.c]
1675 UINT
MenuDrawMenuBar(HDC DC
, LPRECT Rect
, HWND Wnd
, BOOL SuppressDraw
)
1677 ROSMENUINFO MenuInfo
;
1678 HFONT FontOld
= NULL
;
1679 HMENU Menu
= GetMenu(Wnd
);
1681 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1683 return GetSystemMetrics(SM_CYMENU
);
1688 FontOld
= SelectObject(DC
, hMenuFont
);
1690 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1692 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1694 if (NULL
!= FontOld
)
1696 SelectObject(DC
, FontOld
);
1698 return MenuInfo
.Height
;
1702 return DrawMenuBarTemp(Wnd
, DC
, Rect
, Menu
, NULL
);
1706 /***********************************************************************
1709 static BOOL FASTCALL
1710 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1712 TRACE("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1716 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1717 if (0 == (Flags
& TPM_NONOTIFY
))
1719 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1722 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1724 if (0 == (Flags
& TPM_NONOTIFY
))
1726 ROSMENUINFO MenuInfo
;
1728 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1730 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
1732 if (0 == MenuInfo
.Height
)
1734 /* app changed/recreated menu bar entries in WM_INITMENU
1735 Recalculate menu sizes else clicks will not work */
1736 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1737 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1740 /* This makes the menus of applications built with Delphi work.
1741 * It also enables menus to be displayed in more than one window,
1742 * but there are some bugs left that need to be fixed in this case.
1744 if(MenuInfo
.Self
== Menu
)
1747 MenuSetRosMenuInfo(&MenuInfo
);
1755 /***********************************************************************
1758 * Display a popup menu.
1760 static BOOL FASTCALL
1761 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1762 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1764 ROSMENUINFO MenuInfo
;
1765 ROSMENUITEMINFO ItemInfo
;
1768 TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1769 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1771 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1776 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1778 MenuInitRosMenuItemInfo(&ItemInfo
);
1779 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1781 ItemInfo
.fMask
|= MIIM_STATE
;
1782 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1783 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1785 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1786 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1789 /* store the owner for DrawItem */
1790 MenuInfo
.WndOwner
= WndOwner
;
1791 MenuSetRosMenuInfo(&MenuInfo
);
1793 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1795 /* adjust popup menu pos so that it fits within the desktop */
1797 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1798 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1800 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1802 if (0 != XAnchor
&& X
>= Width
- XAnchor
)
1804 X
-= Width
- XAnchor
;
1806 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1808 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1816 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1818 if (0 != YAnchor
&& Y
>= Height
+ YAnchor
)
1820 Y
-= Height
+ YAnchor
;
1822 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1824 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
1833 /* NOTE: In Windows, top menu popup is not owned. */
1834 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
1835 WS_POPUP
, X
, Y
, Width
, Height
,
1836 WndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(WndOwner
, GWLP_HINSTANCE
),
1837 (LPVOID
) MenuInfo
.Self
);
1838 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
1842 if (NULL
== TopPopup
)
1844 TopPopup
= MenuInfo
.Wnd
;
1847 /* Display the window */
1848 SetWindowPos(MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1849 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1850 UpdateWindow(MenuInfo
.Wnd
);
1855 /***********************************************************************
1858 * Find a Sub menu. Return the position of the submenu, and modifies
1859 * *hmenu in case it is found in another sub-menu.
1860 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
1862 static UINT FASTCALL
1863 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
1865 ROSMENUINFO MenuInfo
;
1866 ROSMENUITEMINFO ItemInfo
;
1871 if ((HMENU
) 0xffff == *Menu
1872 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
1874 return NO_SELECTED_ITEM
;
1877 MenuInitRosMenuItemInfo(&ItemInfo
);
1878 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1880 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1882 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1883 return NO_SELECTED_ITEM
;
1885 if (0 == (ItemInfo
.fType
& MF_POPUP
))
1889 if (ItemInfo
.hSubMenu
== SubTarget
)
1891 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1894 SubMenu
= ItemInfo
.hSubMenu
;
1895 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
1896 if (NO_SELECTED_ITEM
!= Pos
)
1902 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1904 return NO_SELECTED_ITEM
;
1907 /***********************************************************************
1910 static void FASTCALL
1911 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
1912 BOOL SendMenuSelect
, HMENU TopMenu
)
1915 ROSMENUITEMINFO ItemInfo
;
1916 ROSMENUINFO TopMenuInfo
;
1919 TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
1921 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
1926 if (MenuInfo
->FocusedItem
== Index
)
1931 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
1933 Dc
= GetDC(MenuInfo
->Wnd
);
1937 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1940 if (NULL
== TopPopup
)
1942 TopPopup
= MenuInfo
->Wnd
;
1945 SelectObject(Dc
, hMenuFont
);
1946 MenuInitRosMenuItemInfo(&ItemInfo
);
1947 /* Clear previous highlighted item */
1948 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1950 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1952 ItemInfo
.fMask
|= MIIM_STATE
;
1953 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1954 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1956 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
1957 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1961 /* Highlight new item (if any) */
1962 MenuInfo
->FocusedItem
= Index
;
1963 MenuSetRosMenuInfo(MenuInfo
);
1964 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1966 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1968 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1970 ItemInfo
.fMask
|= MIIM_STATE
;
1971 ItemInfo
.fState
|= MF_HILITE
;
1972 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1973 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
1974 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1979 SendMessageW(WndOwner
, WM_MENUSELECT
,
1980 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
1981 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1982 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
1986 else if (SendMenuSelect
)
1988 if (NULL
!= TopMenu
)
1990 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
1991 if (NO_SELECTED_ITEM
!= Pos
)
1993 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
1994 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
1996 SendMessageW(WndOwner
, WM_MENUSELECT
,
1997 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1999 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
2005 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2006 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2009 /***********************************************************************
2012 * Moves currently selected item according to the Offset parameter.
2013 * If there is no selection then it should select the last item if
2014 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2016 static void FASTCALL
2017 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2020 ROSMENUITEMINFO ItemInfo
;
2023 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2025 /* Prevent looping */
2026 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
2028 else if (Offset
< -1)
2030 else if (Offset
> 1)
2033 MenuInitRosMenuItemInfo(&ItemInfo
);
2035 OrigPos
= MenuInfo
->FocusedItem
;
2036 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2043 i
= MenuInfo
->FocusedItem
;
2050 /* Clip and wrap around */
2053 i
= MenuInfo
->MenuItemCount
- 1;
2055 else if (i
>= MenuInfo
->MenuItemCount
)
2059 /* If this is a good candidate; */
2060 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2061 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2063 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2064 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2067 } while (i
!= OrigPos
);
2070 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2073 /***********************************************************************
2074 * MenuInitSysMenuPopup
2076 * Grey the appropriate items in System menu.
2079 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2087 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2088 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2089 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2090 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2091 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2092 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2093 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2094 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2095 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2096 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2097 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2099 /* The menu item must keep its state if it's disabled */
2102 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2105 /* Set default menu item */
2106 if(Style
& WS_MINIMIZE
)
2108 DefItem
= SC_RESTORE
;
2112 if(HitTest
== HTCAPTION
)
2114 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2122 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2123 mii
.fMask
|= MIIM_STATE
;
2124 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2125 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2130 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2133 /***********************************************************************
2136 * Display the sub-menu of the selected item of this menu.
2137 * Return the handle of the submenu, or menu if no submenu to display.
2139 static HMENU FASTCALL
2140 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2142 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2144 ROSMENUITEMINFO ItemInfo
;
2145 ROSMENUINFO SubMenuInfo
;
2149 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2151 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2153 return MenuInfo
->Self
;
2156 MenuInitRosMenuItemInfo(&ItemInfo
);
2157 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2159 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2160 return MenuInfo
->Self
;
2162 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2164 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2165 return MenuInfo
->Self
;
2168 /* message must be sent before using item,
2169 because nearly everything may be changed by the application ! */
2171 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2172 if (0 == (Flags
& TPM_NONOTIFY
))
2174 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2175 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2178 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2180 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2181 return MenuInfo
->Self
;
2183 Rect
= ItemInfo
.Rect
;
2185 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2186 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2188 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2190 Dc
= GetDC(MenuInfo
->Wnd
);
2194 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2197 SelectObject(Dc
, hMenuFont
);
2198 ItemInfo
.fMask
|= MIIM_STATE
;
2199 ItemInfo
.fState
|= MF_HILITE
;
2200 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2201 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2202 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2203 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2206 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2207 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2209 ItemInfo
.Rect
= Rect
;
2212 ItemInfo
.fMask
|= MIIM_STATE
;
2213 ItemInfo
.fState
|= MF_MOUSESELECT
;
2214 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2216 if (IS_SYSTEM_MENU(MenuInfo
))
2218 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongW(MenuInfo
->Wnd
, GWL_STYLE
),
2219 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2221 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2222 Rect
.top
= Rect
.bottom
;
2223 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2224 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2228 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2229 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2231 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2232 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2233 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2234 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2235 - GetSystemMetrics(SM_CYBORDER
);
2239 Rect
.left
+= ItemInfo
.Rect
.left
;
2240 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2241 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2242 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2246 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2247 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2248 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2250 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2253 Ret
= ItemInfo
.hSubMenu
;
2254 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2259 /***********************************************************************
2262 * Hide the sub-popup menus of this menu.
2264 static void FASTCALL
2265 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2267 ROSMENUINFO SubMenuInfo
;
2268 ROSMENUITEMINFO ItemInfo
;
2270 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2272 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2274 MenuInitRosMenuItemInfo(&ItemInfo
);
2275 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2276 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2277 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2278 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2280 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2283 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2284 ItemInfo
.fMask
|= MIIM_STATE
;
2285 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2286 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2288 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2289 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2290 DestroyWindow(SubMenuInfo
.Wnd
);
2291 SubMenuInfo
.Wnd
= NULL
;
2292 MenuSetRosMenuInfo(&SubMenuInfo
);
2297 /***********************************************************************
2298 * MenuSwitchTracking
2300 * Helper function for menu navigation routines.
2302 static void FASTCALL
2303 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2305 ROSMENUINFO TopMenuInfo
;
2307 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2309 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2310 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2311 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2313 /* both are top level menus (system and menu-bar) */
2314 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2315 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2316 Mt
->TopMenu
= PtMenuInfo
->Self
;
2320 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2323 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2326 /***********************************************************************
2327 * MenuExecFocusedItem
2329 * Execute a menu item (for instance when user pressed Enter).
2330 * Return the wID of the executed item. Otherwise, -1 indicating
2331 * that no menu item was executed, -2 if a popup is shown;
2332 * Have to receive the flags for the TrackPopupMenu options to avoid
2333 * sending unwanted message.
2337 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2339 ROSMENUITEMINFO ItemInfo
;
2342 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2344 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2349 MenuInitRosMenuItemInfo(&ItemInfo
);
2350 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2352 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2356 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2358 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2360 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2361 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2363 /* If TPM_RETURNCMD is set you return the id, but
2364 do not send a message to the owner */
2365 if (0 == (Flags
& TPM_RETURNCMD
))
2367 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2369 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2370 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2374 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2375 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2376 MenuInfo
->FocusedItem
,
2377 (LPARAM
)MenuInfo
->Self
);
2379 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2383 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2389 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2396 /***********************************************************************
2399 * Return TRUE if we can go on with menu tracking.
2401 static BOOL FASTCALL
2402 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2405 ROSMENUINFO MenuInfo
;
2406 ROSMENUITEMINFO Item
;
2408 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2412 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2416 if (IS_SYSTEM_MENU(&MenuInfo
))
2422 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2424 MenuInitRosMenuItemInfo(&Item
);
2425 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2427 MenuCleanupRosMenuItemInfo(&Item
);
2431 if (!(Item
.fType
& MF_SEPARATOR
) &&
2432 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2434 if (MenuInfo
.FocusedItem
!= Index
)
2436 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2439 /* If the popup menu is not already "popped" */
2440 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2442 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2446 MenuCleanupRosMenuItemInfo(&Item
);
2451 /* else the click was on the menu bar, finish the tracking */
2456 /***********************************************************************
2459 * Return the value of MenuExecFocusedItem if
2460 * the selected item was not a popup. Else open the popup.
2461 * A -1 return value indicates that we go on with menu tracking.
2465 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2468 ROSMENUINFO MenuInfo
;
2469 ROSMENUITEMINFO ItemInfo
;
2471 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2476 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2481 if (! IS_SYSTEM_MENU(&MenuInfo
))
2483 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2485 MenuInitRosMenuItemInfo(&ItemInfo
);
2486 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2487 MenuInfo
.FocusedItem
== Id
)
2489 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2491 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2492 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2493 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2495 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2497 /* If we are dealing with the top-level menu */
2498 /* and this is a click on an already "popped" item: */
2499 /* Stop the menu tracking and close the opened submenus */
2500 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2502 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2506 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2507 MenuInfo
.TimeToHide
= TRUE
;
2508 MenuSetRosMenuInfo(&MenuInfo
);
2514 /***********************************************************************
2517 * Walks menu chain trying to find a menu pt maps to.
2519 static HMENU FASTCALL
2520 MenuPtMenu(HMENU Menu
, POINT Pt
)
2522 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2523 ROSMENUINFO MenuInfo
;
2524 ROSMENUITEMINFO ItemInfo
;
2528 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2533 /* try subpopup first (if any) */
2534 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2536 MenuInitRosMenuItemInfo(&ItemInfo
);
2537 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2538 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2539 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2541 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2544 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2548 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2551 /* check the current window (avoiding WM_HITTEST) */
2552 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2553 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2555 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2560 else if (HTSYSMENU
== Ht
)
2562 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2564 else if (HTMENU
== Ht
)
2566 Ret
= GetMenu(MenuInfo
.Wnd
);
2572 /***********************************************************************
2575 * Return TRUE if we can go on with menu tracking.
2577 static BOOL FASTCALL
2578 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2581 ROSMENUINFO MenuInfo
;
2582 ROSMENUITEMINFO ItemInfo
;
2586 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2590 if (IS_SYSTEM_MENU(&MenuInfo
))
2596 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2601 Index
= NO_SELECTED_ITEM
;
2604 if (NO_SELECTED_ITEM
== Index
)
2606 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2607 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2609 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2613 else if (MenuInfo
.FocusedItem
!= Index
)
2615 MenuInitRosMenuItemInfo(&ItemInfo
);
2616 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2617 !(ItemInfo
.fType
& MF_SEPARATOR
))
2619 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2620 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2621 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2623 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2629 /******************************************************************************
2631 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2633 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2636 PROSMENUITEMINFO MenuItems
;
2638 i
= MenuInfo
->FocusedItem
;
2639 if (NO_SELECTED_ITEM
== i
)
2644 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2646 return NO_SELECTED_ITEM
;
2649 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2651 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2657 return NO_SELECTED_ITEM
;
2660 /******************************************************************************
2662 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2664 static UINT FASTCALL
2665 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2668 PROSMENUITEMINFO MenuItems
;
2670 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2672 return NO_SELECTED_ITEM
;
2675 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2677 return NO_SELECTED_ITEM
;
2680 /* Find the start of the column */
2682 for (i
= MenuInfo
->FocusedItem
;
2683 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2691 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2692 return NO_SELECTED_ITEM
;
2695 for (--i
; 0 != i
; --i
)
2697 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2703 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2704 TRACE("ret %d.\n", i
);
2709 /***********************************************************************
2712 * Return the handle of the selected sub-popup menu (if any).
2714 static HMENU FASTCALL
2715 MenuGetSubPopup(HMENU Menu
)
2717 ROSMENUINFO MenuInfo
;
2718 ROSMENUITEMINFO ItemInfo
;
2720 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2721 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2726 MenuInitRosMenuItemInfo(&ItemInfo
);
2727 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2729 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2732 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2734 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2735 return ItemInfo
.hSubMenu
;
2738 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2742 /***********************************************************************
2745 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2747 static LRESULT FASTCALL
2748 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2750 ROSMENUINFO TopMenuInfo
;
2751 ROSMENUINFO MenuInfo
;
2753 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2755 return (LRESULT
) FALSE
;
2758 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2759 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2761 MDINEXTMENU NextMenu
;
2766 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2767 NextMenu
.hmenuNext
= NULL
;
2768 NextMenu
.hwndNext
= NULL
;
2769 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2771 TRACE("%p [%p] -> %p [%p]\n",
2772 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2774 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2776 DWORD Style
= GetWindowLongW(Mt
->OwnerWnd
, GWL_STYLE
);
2777 NewWnd
= Mt
->OwnerWnd
;
2778 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2780 /* switch to the menu bar */
2782 if (0 != (Style
& WS_CHILD
)
2783 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2790 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2794 Id
= MenuInfo
.MenuItemCount
- 1;
2797 else if (0 != (Style
& WS_SYSMENU
))
2799 /* switch to the system menu */
2800 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2807 else /* application returned a new menu to switch to */
2809 NewMenu
= NextMenu
.hmenuNext
;
2810 NewWnd
= NextMenu
.hwndNext
;
2812 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2814 DWORD Style
= GetWindowLongW(NewWnd
, GWL_STYLE
);
2816 if (0 != (Style
& WS_SYSMENU
)
2817 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2819 /* get the real system menu */
2820 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2822 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2824 /* FIXME: Not sure what to do here;
2825 * perhaps try to track NewMenu as a popup? */
2827 WARN(" -- got confused.\n");
2837 if (NewMenu
!= Mt
->TopMenu
)
2839 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2841 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2843 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2847 if (NewWnd
!= Mt
->OwnerWnd
)
2849 Mt
->OwnerWnd
= NewWnd
;
2850 SetCapture(Mt
->OwnerWnd
);
2851 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2854 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2855 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2857 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2866 /***********************************************************************
2869 * The idea is not to show the popup if the next input message is
2870 * going to hide it anyway.
2872 static BOOL FASTCALL
2873 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2877 Msg
.hwnd
= Mt
->OwnerWnd
;
2879 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2880 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2885 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2886 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2888 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2889 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2890 if (WM_KEYDOWN
== Msg
.message
2891 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2893 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2900 /* failures go through this */
2901 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2906 /***********************************************************************
2909 * Handle a VK_ESCAPE key event in a menu.
2911 static BOOL FASTCALL
2912 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2914 BOOL EndMenu
= TRUE
;
2915 ROSMENUINFO MenuInfo
;
2916 HMENU MenuTmp
, MenuPrev
;
2918 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2920 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2921 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2923 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2925 /* close topmost popup */
2926 while (MenuTmp
!= Mt
->CurrentMenu
)
2929 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2932 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2934 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
2936 Mt
->CurrentMenu
= MenuPrev
;
2944 /***********************************************************************
2947 * Handle a VK_LEFT key event in a menu.
2949 static void FASTCALL
2950 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2952 ROSMENUINFO MenuInfo
;
2953 ROSMENUINFO TopMenuInfo
;
2954 ROSMENUINFO PrevMenuInfo
;
2955 HMENU MenuTmp
, MenuPrev
;
2958 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2960 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2965 /* Try to move 1 column left (if possible) */
2966 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
2968 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2970 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
2975 /* close topmost popup */
2976 while (MenuTmp
!= Mt
->CurrentMenu
)
2979 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2982 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
2986 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
2987 Mt
->CurrentMenu
= MenuPrev
;
2989 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2993 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
2995 /* move menu bar selection if no more popups are left */
2997 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
2999 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3002 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3004 /* A sublevel menu was displayed - display the next one
3005 * unless there is another displacement coming up */
3007 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3008 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3010 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3017 /***********************************************************************
3020 * Handle a VK_RIGHT key event in a menu.
3022 static void FASTCALL
3023 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3026 ROSMENUINFO MenuInfo
;
3027 ROSMENUINFO CurrentMenuInfo
;
3030 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3031 Mt
->CurrentMenu
, Mt
->TopMenu
);
3033 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3037 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3039 /* If already displaying a popup, try to display sub-popup */
3041 MenuTmp
= Mt
->CurrentMenu
;
3042 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3044 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3047 /* if subpopup was displayed then we are done */
3048 if (MenuTmp
!= Mt
->CurrentMenu
)
3054 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3059 /* Check to see if there's another column */
3060 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3062 TRACE("Going to %d.\n", NextCol
);
3063 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3065 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3070 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3072 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3074 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3075 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3082 /* try to move to the next item */
3083 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
3085 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3088 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3090 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3091 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3093 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3100 /***********************************************************************
3103 * Find the menu item selected by a key press.
3104 * Return item id, -1 if none, -2 if we should close the menu.
3106 static UINT FASTCALL
3107 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
3108 WCHAR Key
, BOOL ForceMenuChar
)
3110 ROSMENUINFO SysMenuInfo
;
3111 PROSMENUITEMINFO Items
, ItemInfo
;
3115 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
3117 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
3119 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
3121 MenuInfo
= &SysMenuInfo
;
3129 if (NULL
!= MenuInfo
)
3131 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
3135 if (! ForceMenuChar
)
3137 Key
= toupperW(Key
);
3139 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
3141 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
3143 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
3146 p
= strchrW(p
+ 2, '&');
3148 while (NULL
!= p
&& L
'&' == p
[1]);
3149 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
3157 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
3158 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
3159 if (2 == HIWORD(MenuChar
))
3161 return LOWORD(MenuChar
);
3163 if (1 == HIWORD(MenuChar
))
3172 /***********************************************************************
3175 * Menu tracking code.
3178 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3179 HWND Wnd
, const RECT
*Rect
)
3182 ROSMENUINFO MenuInfo
;
3183 ROSMENUITEMINFO ItemInfo
;
3185 INT ExecutedMenuId
= -1;
3187 BOOL EnterIdleSent
= FALSE
;
3190 Mt
.CurrentMenu
= Menu
;
3196 TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3197 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3198 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3201 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3206 if (0 != (Flags
& TPM_BUTTONDOWN
))
3208 /* Get the result in order to start the tracking or not */
3209 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3210 fEndMenu
= ! fRemove
;
3213 SetCapture(Mt
.OwnerWnd
);
3214 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
.OwnerWnd
);
3218 /* we have to keep the message in the queue until it's
3219 * clear that menu loop is not over yet. */
3223 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3225 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3229 /* remove the message from the queue */
3230 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3234 if (! EnterIdleSent
)
3236 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3237 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3238 EnterIdleSent
= TRUE
;
3239 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3245 /* check if EndMenu() tried to cancel us, by posting this message */
3246 if (WM_CANCELMODE
== Msg
.message
)
3248 /* we are now out of the loop */
3251 /* remove the message from the queue */
3252 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3254 /* break out of internal loop, ala ESCAPE */
3258 TranslateMessage(&Msg
);
3261 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3263 EnterIdleSent
= FALSE
;
3267 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3270 * Use the mouse coordinates in lParam instead of those in the MSG
3271 * struct to properly handle synthetic messages. They are already
3272 * in screen coordinates.
3274 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3275 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3277 /* Find a menu for this mouse event */
3278 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3282 /* no WM_NC... messages in captured state */
3284 case WM_RBUTTONDBLCLK
:
3285 case WM_RBUTTONDOWN
:
3286 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3291 case WM_LBUTTONDBLCLK
:
3292 case WM_LBUTTONDOWN
:
3293 /* If the message belongs to the menu, removes it from the queue */
3294 /* Else, end menu tracking */
3295 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3296 fEndMenu
= ! fRemove
;
3300 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3306 /* Check if a menu was selected by the mouse */
3309 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3311 /* End the loop if ExecutedMenuId is an item ID */
3312 /* or if the job was done (ExecutedMenuId = 0). */
3313 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3317 /* No menu was selected by the mouse */
3318 /* if the function was called by TrackPopupMenu, continue
3319 with the menu tracking. If not, stop it */
3320 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3327 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3331 } /* switch(Msg.message) - mouse */
3333 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3335 fRemove
= TRUE
; /* Keyboard messages are always removed */
3347 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3349 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3355 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3357 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3358 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3362 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3363 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3365 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3367 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3369 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3373 else /* otherwise try to move selection */
3375 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3381 MenuKeyLeft(&Mt
, Flags
);
3385 MenuKeyRight(&Mt
, Flags
);
3389 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3395 hi
.cbSize
= sizeof(HELPINFO
);
3396 hi
.iContextType
= HELPINFO_MENUITEM
;
3397 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3399 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3405 MenuInitRosMenuItemInfo(&ItemInfo
);
3406 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3407 MenuInfo
.FocusedItem
,
3410 hi
.iCtrlId
= ItemInfo
.wID
;
3416 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3419 hi
.hItemHandle
= Menu
;
3420 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3421 hi
.MousePos
= Msg
.pt
;
3422 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3429 break; /* WM_KEYDOWN */
3436 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3440 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3442 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3443 fEndMenu
= (ExecutedMenuId
!= -2);
3447 /* Hack to avoid control chars. */
3448 /* We will find a better way real soon... */
3449 if (Msg
.wParam
< 32)
3454 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3455 LOWORD(Msg
.wParam
), FALSE
);
3456 if ((UINT
) -2 == Pos
)
3460 else if ((UINT
) -1 == Pos
)
3466 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3467 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3468 fEndMenu
= (-2 != ExecutedMenuId
);
3472 } /* switch(msg.message) - kbd */
3476 PeekMessageW( &Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3477 DispatchMessageW(&Msg
);
3486 /* finally remove message from the queue */
3488 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3490 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3494 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3498 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3499 SetCapture(NULL
); /* release the capture */
3501 /* If dropdown is still painted and the close box is clicked on
3502 then the menu will be destroyed as part of the DispatchMessage above.
3503 This will then invalidate the menu handle in Mt.hTopMenu. We should
3504 check for this first. */
3505 if (IsMenu(Mt
.TopMenu
))
3507 if (IsWindow(Mt
.OwnerWnd
))
3509 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3511 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3513 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3515 DestroyWindow(MenuInfo
.Wnd
);
3516 MenuInfo
.Wnd
= NULL
;
3518 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3521 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3524 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3526 /* Reset the variable for hiding menu */
3527 MenuInfo
.TimeToHide
= FALSE
;
3528 MenuSetRosMenuInfo(&MenuInfo
);
3532 /* The return value is only used by TrackPopupMenu */
3533 if (!(Flags
& TPM_RETURNCMD
)) return TRUE
;
3534 if (ExecutedMenuId
< 0) ExecutedMenuId
= 0;
3535 return ExecutedMenuId
;
3538 /***********************************************************************
3541 static BOOL FASTCALL
3542 MenuExitTracking(HWND Wnd
)
3544 TRACE("hwnd=%p\n", Wnd
);
3546 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3553 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3555 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3556 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3558 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, Pt
.x
, Pt
.y
);
3562 /* map point to parent client coordinates */
3563 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3564 if (Parent
!= GetDesktopWindow())
3566 ScreenToClient(Parent
, &Pt
);
3569 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3570 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3571 MenuExitTracking(Wnd
);
3577 MenuTrackKbdMenuBar(HWND hWnd
, UINT wParam
, WCHAR wChar
)
3579 UINT uItem
= NO_SELECTED_ITEM
;
3581 ROSMENUINFO MenuInfo
;
3582 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3584 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd
, wParam
, wChar
);
3586 /* find window that has a menu */
3588 while (!((GetWindowLongW( hWnd
, GWL_STYLE
) &
3589 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3590 if (!(hWnd
= GetAncestor( hWnd
, GA_PARENT
))) return;
3592 /* check if we have to track a system menu */
3594 hTrackMenu
= GetMenu( hWnd
);
3595 if (!hTrackMenu
|| IsIconic(hWnd
) || wChar
== ' ' )
3597 if (!(GetWindowLongW( hWnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3598 hTrackMenu
= NtUserGetSystemMenu(hWnd
, FALSE
);
3600 wParam
|= HTSYSMENU
; /* prevent item lookup */
3603 if (!IsMenu( hTrackMenu
)) return;
3605 MenuInitTracking( hWnd
, hTrackMenu
, FALSE
, wFlags
);
3607 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3612 if( wChar
&& wChar
!= ' ' )
3614 uItem
= MenuFindItemByKey( hWnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3615 if ( uItem
>= (UINT
)(-2) )
3617 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3618 /* schedule end of menu tracking */
3619 wFlags
|= TF_ENDMENU
;
3624 MenuSelectItem( hWnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3626 if (wParam
& HTSYSMENU
)
3628 /* prevent sysmenu activation for managed windows on Alt down/up */
3629 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3630 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3634 if( uItem
== NO_SELECTED_ITEM
)
3635 MenuMoveSelection( hWnd
, &MenuInfo
, ITEM_NEXT
);
3637 PostMessageW( hWnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3641 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hWnd
, NULL
);
3642 MenuExitTracking( hWnd
);
3648 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3649 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3651 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3653 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3654 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3655 * MFT_STRING is replaced by MIIM_STRING.
3656 * (So, I guess we should use MIIM_STRING only for strings?)
3658 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3660 * Based on wine, SetMenuItemInfo_common:
3661 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3662 * it will result in a error.
3663 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3664 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3671 LPMENUITEMINFOW mii
,
3678 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3680 if(Flags
& MF_BITMAP
)
3682 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3683 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3685 if (Flags
& MF_HELP
)
3687 /* increase ident */
3688 mii
->fType
|= MF_HELP
;
3691 else if(Flags
& MF_OWNERDRAW
)
3693 mii
->fType
|= MFT_OWNERDRAW
;
3694 mii
->fMask
|= MIIM_DATA
;
3695 mii
->dwItemData
= (DWORD
) NewItem
;
3697 else if (Flags
& MF_SEPARATOR
)
3699 mii
->fType
|= MFT_SEPARATOR
;
3700 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3701 Flags
|= MF_GRAYED
|MF_DISABLED
;
3703 else /* Default action MF_STRING. */
3705 /* Item beginning with a backspace is a help item */
3706 if (NewItem
!= NULL
)
3710 if (*NewItem
== '\b')
3712 mii
->fType
|= MF_HELP
;
3718 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3719 if (*NewItemA
== '\b')
3721 mii
->fType
|= MF_HELP
;
3723 NewItem
= (LPCWSTR
) NewItemA
;
3727 if (Flags
& MF_HELP
)
3728 mii
->fType
|= MF_HELP
;
3729 mii
->fMask
|= MIIM_STRING
;
3730 mii
->fType
|= MFT_STRING
; /* Zero */
3731 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3733 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3735 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3739 mii
->fType
|= MFT_SEPARATOR
;
3740 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3741 Flags
|= MF_GRAYED
|MF_DISABLED
;
3745 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3747 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3750 if(Flags
& MF_MENUBREAK
)
3752 mii
->fType
|= MFT_MENUBREAK
;
3754 else if(Flags
& MF_MENUBARBREAK
)
3756 mii
->fType
|= MFT_MENUBARBREAK
;
3759 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3761 if (Flags
& MF_GRAYED
)
3762 mii
->fState
|= MF_GRAYED
;
3764 if (Flags
& MF_DISABLED
)
3765 mii
->fState
|= MF_DISABLED
;
3767 mii
->fMask
|= MIIM_STATE
;
3769 else if (Flags
& MF_HILITE
)
3771 mii
->fState
|= MF_HILITE
;
3772 mii
->fMask
|= MIIM_STATE
;
3774 else /* default state */
3776 mii
->fState
|= MFS_ENABLED
;
3777 mii
->fMask
|= MIIM_STATE
;
3780 if(Flags
& MF_POPUP
)
3782 mii
->fType
|= MF_POPUP
;
3783 mii
->fMask
|= MIIM_SUBMENU
;
3784 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3788 mii
->fMask
|= MIIM_ID
;
3789 mii
->wID
= (UINT
)IDNewItem
;
3795 /* FUNCTIONS *****************************************************************/
3798 MenuIsStringItem(ULONG TypeData)
3800 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3808 AppendMenuA(HMENU hMenu
,
3810 UINT_PTR uIDNewItem
,
3813 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3822 AppendMenuW(HMENU hMenu
,
3824 UINT_PTR uIDNewItem
,
3827 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3836 CheckMenuItem(HMENU hmenu
,
3840 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3845 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3848 PROSMENUITEMINFO Items
= NULL
;
3849 UINT cChecked
, cUnchecked
;
3853 if(idFirst
> idLast
)
3856 ItemCount
= GetMenuItemCount(hMenu
);
3858 //mi.cbSize = sizeof(ROSMENUINFO);
3859 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3862 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3864 ERR("MenuGetAllRosMenuItemInfo failed\n");
3868 cChecked
= cUnchecked
= 0;
3870 for (i
= 0 ; i
< ItemCount
; i
++)
3873 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3874 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3876 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3878 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3881 if (uFlags
& MF_BYPOSITION
)
3883 if (i
< idFirst
|| i
> idLast
)
3898 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3901 if (Items
[i
].wID
== idCheck
)
3915 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
3918 Items
[i
].fType
|= MFT_RADIOCHECK
;
3919 Items
[i
].fState
|= MFS_CHECKED
;
3923 Items
[i
].fState
&= ~MFS_CHECKED
;
3926 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
3928 ERR("MenuSetRosMenuItemInfo failed\n");
3933 HeapFree(GetProcessHeap(), 0, Items
);
3935 *pChecked
+= cChecked
;
3936 *pUnchecked
+= cUnchecked
;
3938 if (cChecked
|| cUnchecked
)
3948 CheckMenuRadioItem(HMENU hmenu
,
3955 UINT cUnchecked
= 0;
3956 UINT cMenuChanged
= 0;
3958 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
3961 if (cMenuChanged
> 1)
3968 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
3971 return (cChecked
!= 0);
3982 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
3990 CreatePopupMenu(VOID
)
3993 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4001 DrawMenuBar(HWND hWnd
)
4003 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4004 ROSMENUINFO MenuInfo
;
4006 hMenu
= GetMenu(hWnd
);
4009 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4010 MenuInfo
.Height
= 0; // make sure to recalc size
4011 MenuSetRosMenuInfo(&MenuInfo
);
4012 /* The wine method doesn't work and I suspect it's more effort
4013 then hackfix solution
4014 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4015 SWP_NOZORDER | SWP_FRAMECHANGED );
4018 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4027 EnableMenuItem(HMENU hMenu
,
4031 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4041 guii
.cbSize
= sizeof(GUITHREADINFO
);
4042 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4044 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4056 return NtUserGetMenu(hWnd
);
4064 GetMenuCheckMarkDimensions(VOID
)
4066 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4067 GetSystemMetrics(SM_CYMENUCHECK
)));
4075 GetMenuDefaultItem(HMENU hMenu
,
4079 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4087 GetMenuInfo(HMENU hmenu
,
4093 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4096 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4097 mi
.cbSize
= sizeof(MENUINFO
);
4098 mi
.fMask
= lpcmi
->fMask
;
4100 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4102 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4111 GetMenuItemCount(HMENU Menu
)
4113 ROSMENUINFO MenuInfo
;
4115 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4123 GetMenuItemID(HMENU hMenu
,
4126 ROSMENUITEMINFO mii
;
4128 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4129 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4131 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4136 if (NULL
!= mii
.hSubMenu
)
4157 LPMENUITEMINFOA mii
)
4163 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4164 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4166 SetLastError(ERROR_INVALID_PARAMETER
);
4170 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4172 /* No text requested, just pass on */
4173 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4176 AnsiBuffer
= mii
->dwTypeData
;
4177 Count
= miiW
.cch
= mii
->cch
;
4178 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4179 miiW
.dwTypeData
= 0;
4183 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4184 miiW
.cch
* sizeof(WCHAR
));
4185 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4186 miiW
.dwTypeData
[0] = 0;
4189 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4191 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4195 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4197 if (!AnsiBuffer
|| !Count
)
4199 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4200 mii
->dwTypeData
= AnsiBuffer
;
4201 mii
->cch
= miiW
.cch
;
4205 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4209 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4213 if (Count
> miiW
.cch
)
4215 AnsiBuffer
[miiW
.cch
] = 0;
4217 mii
->cch
= mii
->cch
;
4225 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4226 mii
->dwTypeData
= AnsiBuffer
;
4240 LPMENUITEMINFOW mii
)
4246 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4247 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4249 SetLastError(ERROR_INVALID_PARAMETER
);
4253 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4255 /* No text requested, just pass on */
4256 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4259 String
= mii
->dwTypeData
;
4261 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4262 miiW
.dwTypeData
= 0;
4266 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4267 miiW
.cch
* sizeof(WCHAR
));
4268 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4269 miiW
.dwTypeData
[0] = 0;
4272 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4274 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4278 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4280 if (!String
|| !Count
)
4282 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4283 mii
->dwTypeData
= String
; // may not be zero.
4284 mii
->cch
= miiW
.cch
;
4288 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4290 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4293 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4294 mii
->dwTypeData
= String
;
4295 mii
->cch
= strlenW(String
);
4310 ROSMENUINFO MenuInfo
;
4311 ROSMENUITEMINFO mii
;
4312 memset( &mii
, 0, sizeof(mii
) );
4313 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4314 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4317 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4322 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4326 nSubItems
= MenuInfo
.MenuItemCount
;
4328 /* FIXME - ported from wine, does that work (0xff)? */
4329 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4330 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4332 return (UINT
)-1; /* Invalid submenu */
4335 /* FIXME - ported from wine, does that work? */
4336 return (mii
.fType
| mii
.fState
);
4356 memset( &mii
, 0, sizeof(mii
) );
4357 mii
.dwTypeData
= lpString
;
4358 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4359 mii
.fType
= MFT_STRING
;
4360 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4361 mii
.cch
= nMaxCount
;
4363 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4383 memset( &miiW
, 0, sizeof(miiW
) );
4384 miiW
.dwTypeData
= lpString
;
4385 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4386 miiW
.fType
= MFT_STRING
;
4387 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4388 miiW
.cch
= nMaxCount
;
4390 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4408 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4409 mi
.fMask
= MIIM_SUBMENU
;
4411 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4413 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4430 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4432 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4445 UINT_PTR uIDNewItem
,
4449 memset( &mii
, 0, sizeof(mii
) );
4450 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4451 mii
.fMask
= MIIM_FTYPE
;
4453 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4456 (LPCWSTR
) lpNewItem
,
4459 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4473 LPCMENUITEMINFOA lpmii
)
4476 UNICODE_STRING MenuText
;
4478 BOOL CleanHeap
= FALSE
;
4481 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4482 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4484 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4486 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4488 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4491 /* copy the text string */
4492 if (((mi
.fMask
& MIIM_STRING
) ||
4493 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4494 && mi
.dwTypeData
!= NULL
)
4496 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4497 if (!NT_SUCCESS (Status
))
4499 SetLastError (RtlNtStatusToDosError(Status
));
4502 mi
.dwTypeData
= MenuText
.Buffer
;
4503 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4506 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4508 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4523 LPCMENUITEMINFOW lpmii
)
4526 UNICODE_STRING MenuText
;
4529 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4530 if a bad user passes bad data, we crash his process instead of the
4533 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4534 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4536 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4538 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4540 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4543 /* copy the text string */
4544 if (((mi
.fMask
& MIIM_STRING
) ||
4545 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4546 && mi
.dwTypeData
!= NULL
)
4548 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4549 mi
.dwTypeData
= MenuText
.Buffer
;
4550 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4552 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4567 UINT_PTR uIDNewItem
,
4571 memset( &mii
, 0, sizeof(mii
) );
4572 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4573 mii
.fMask
= MIIM_FTYPE
;
4575 MenuSetItemData( &mii
,
4581 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4593 ROSMENUINFO MenuInfo
;
4595 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4603 LoadMenuA(HINSTANCE hInstance
,
4606 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4607 if (Resource
== NULL
)
4611 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4619 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4621 return(LoadMenuIndirectW(lpMenuTemplate
));
4629 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4632 WORD version
, offset
;
4633 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4635 version
= GET_WORD(p
);
4640 case 0: /* standard format is version of 0 */
4641 offset
= GET_WORD(p
);
4642 p
+= sizeof(WORD
) + offset
;
4643 if (!(hMenu
= CreateMenu())) return 0;
4644 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4650 case 1: /* extended format is version of 1 */
4651 offset
= GET_WORD(p
);
4652 p
+= sizeof(WORD
) + offset
;
4653 if (!(hMenu
= CreateMenu())) return 0;
4654 if (!MENUEX_ParseResource(p
, hMenu
))
4656 DestroyMenu( hMenu
);
4661 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4671 LoadMenuW(HINSTANCE hInstance
,
4674 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4675 if (Resource
== NULL
)
4679 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4693 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4706 UINT_PTR uIDNewItem
,
4710 ROSMENUITEMINFO rmii
;
4712 memset( &mii
, 0, sizeof(mii
) );
4713 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4714 mii
.fMask
= MIIM_FTYPE
;
4716 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4720 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4722 MenuInitRosMenuItemInfo( &rmii
);
4724 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4726 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4727 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4729 MenuCleanupRosMenuItemInfo( &rmii
);
4731 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4734 (LPCWSTR
) lpNewItem
,
4737 return SetMenuItemInfoA( hMnu
,
4739 (BOOL
)(MF_BYPOSITION
& uFlags
),
4753 UINT_PTR uIDNewItem
,
4757 ROSMENUITEMINFO rmii
;
4759 memset ( &mii
, 0, sizeof(mii
) );
4760 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4761 mii
.fMask
= MIIM_FTYPE
;
4763 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4765 mi
.Height
= 0; // Force size recalculation.
4767 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4769 MenuInitRosMenuItemInfo( &rmii
);
4771 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4773 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4774 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4776 MenuCleanupRosMenuItemInfo( &rmii
);
4778 /* Init new data for this menu item */
4779 MenuSetItemData( &mii
,
4785 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4786 return SetMenuItemInfoW( hMnu
,
4788 (BOOL
)(MF_BYPOSITION
& uFlags
),
4800 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4815 if(lpcmi
->cbSize
!= sizeof(MENUINFO
))
4818 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4819 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4832 HBITMAP hBitmapUnchecked
,
4833 HBITMAP hBitmapChecked
)
4835 ROSMENUITEMINFO uItem
;
4836 memset ( &uItem
, 0, sizeof(uItem
) );
4837 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4839 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4840 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4842 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4844 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4846 else /* Install new bitmaps */
4848 uItem
.hbmpChecked
= hBitmapChecked
;
4849 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4850 uItem
.fState
|= MF_USECHECKBITMAPS
;
4852 return NtUserMenuItemInfo(hMenu
, uPosition
,
4853 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4866 LPCMENUITEMINFOA lpmii
)
4868 MENUITEMINFOW MenuItemInfoW
;
4869 UNICODE_STRING UnicodeString
;
4871 ULONG Result
= FALSE
;
4873 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4875 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4877 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4878 MenuItemInfoW
.hbmpItem
= NULL
;
4881 * MIIM_STRING == good
4882 * MIIM_TYPE & MFT_STRING == good
4883 * MIIM_STRING & MFT_STRING == good
4884 * MIIM_STRING & MFT_OWNERSRAW == good
4886 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4887 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4888 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4889 && MenuItemInfoW
.dwTypeData
!= NULL
)
4891 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
4892 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
4893 (LPSTR
)MenuItemInfoW
.dwTypeData
);
4894 if (!NT_SUCCESS (Status
))
4896 SetLastError (RtlNtStatusToDosError(Status
));
4899 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
4900 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4904 UnicodeString
.Buffer
= NULL
;
4907 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
4908 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
4910 if (UnicodeString
.Buffer
!= NULL
)
4912 RtlFreeUnicodeString(&UnicodeString
);
4928 LPCMENUITEMINFOW lpmii
)
4930 MENUITEMINFOW MenuItemInfoW
;
4933 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4935 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4937 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4938 MenuItemInfoW
.hbmpItem
= NULL
;
4941 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4942 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4943 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4944 && MenuItemInfoW
.dwTypeData
!= NULL
)
4946 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
4948 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
4949 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
4965 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4970 SetLastError(ERROR_INVALID_MENU_HANDLE
);
4973 return NtUserSetSystemMenu(hwnd
, hMenu
);
4993 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
4995 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4996 if (0 == (Flags
& TPM_NONOTIFY
))
4998 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5001 if (MenuShowPopup(Wnd
, Menu
, 0, x
, y
, 0, 0 ))
5003 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5005 MenuExitTracking(Wnd
);
5024 /* Not fully implemented */
5025 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5026 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5030 // Example for the Win32/User32 rewrite.
5031 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5045 return NtUserTrackPopupMenuEx( Menu
,
5050 NULL
); // LPTPMPARAMS is null
5059 GetMenuContextHelpId(HMENU hmenu
)
5062 mi
.cbSize
= sizeof(ROSMENUINFO
);
5063 mi
.fMask
= MIM_HELPID
;
5065 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5067 return mi
.dwContextHelpID
;
5112 LPCWSTR lpszNewItem
,
5117 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5118 for MF_DELETE. We should check the parameters for all others
5119 MF_* actions also (anybody got a doc on ChangeMenu?).
5122 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5125 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5128 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5131 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5134 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5135 flags
&~ MF_REMOVE
);
5137 default : /* MF_INSERT */
5138 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5155 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5156 for MF_DELETE. We should check the parameters for all others
5157 MF_* actions also (anybody got a doc on ChangeMenu?).
5160 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5163 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5166 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5169 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5172 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5173 flags
&~ MF_REMOVE
);
5175 default : /* MF_INSERT */
5176 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);