3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * Partly based on Wine code
6 * Copyright 1993 Martin Ayotte
7 * Copyright 1994 Alexandre Julliard
8 * Copyright 1997 Morten Welinder
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* $Id: menu.c,v 1.50 2004/02/22 23:40:58 gvg Exp $
26 * PROJECT: ReactOS user32.dll
27 * FILE: lib/user32/windows/menu.c
29 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
31 * 09-05-2001 CSH Created
34 /* INCLUDES ******************************************************************/
46 #include <user32/callback.h>
47 #include "user32/regcontrol.h"
48 #include "../controls/controls.h"
53 /* internal popup menu window messages */
54 #define MM_SETMENUHANDLE (WM_USER + 0)
55 #define MM_GETMENUHANDLE (WM_USER + 1)
57 /* Internal MenuTrackMenu() flags */
58 #define TPM_INTERNAL 0xF0000000
59 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
60 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
61 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
63 /* TYPES *********************************************************************/
65 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
67 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
68 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
69 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
71 #define IS_SYSTEM_MENU(MenuInfo) \
72 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
74 #define IS_SYSTEM_POPUP(MenuInfo) \
75 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
77 #define MENU_BAR_ITEMS_SPACE (12)
78 #define SEPARATOR_HEIGHT (5)
79 #define MENU_TAB_SPACE (8)
85 #define MF_END (0x0080)
89 #define MIIM_STRING (0x00000040)
92 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
93 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
94 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
95 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
97 /* internal flags for menu tracking */
99 #define TF_ENDMENU 0x0001
100 #define TF_SUSPENDPOPUP 0x0002
101 #define TF_SKIPREMOVE 0x0004
106 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
107 HMENU TopMenu
; /* initial menu */
108 HWND OwnerWnd
; /* where notifications are sent */
112 static LRESULT WINAPI
PopupMenuWndProcW(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
114 /*********************************************************************
115 * PopupMenu class descriptor
117 const struct builtin_class_descr POPUPMENU_builtin_class
=
119 POPUPMENU_CLASS_ATOMW
, /* name */
120 CS_GLOBALCLASS
| CS_SAVEBITS
| CS_DBLCLKS
, /* style */
121 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
122 (WNDPROC
) NULL
, /* FIXME - procA */
123 sizeof(MENUINFO
*), /* extra */
124 (LPCWSTR
) IDC_ARROW
, /* cursor */
125 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
129 /* INTERNAL FUNCTIONS ********************************************************/
131 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
132 * Of course I didnt copy the ASM code because we want this to be portable
133 * and it needs to go away.
137 #define GET_WORD(ptr) (*(WORD *)(ptr))
140 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
143 HFONT hMenuFont
= NULL
;
144 HFONT hMenuFontBold
= NULL
;
146 /* Flag set by EndMenu() to force an exit from menu tracking */
147 static BOOL fEndMenu
= FALSE
;
149 /* Use global popup window because there's no way 2 menus can
150 * be tracked at the same time. */
151 static HWND TopPopup
;
153 /* Dimension of the menu bitmaps */
154 static WORD ArrowBitmapWidth
= 0/*, ArrowBitmapHeight = 0*/;
157 /***********************************************************************
160 * Get full information about menu
163 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
165 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
166 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
168 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
171 /***********************************************************************
174 * Set full information about menu
177 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
179 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
180 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
182 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
185 /***********************************************************************
186 * MenuInitRosMenuItemInfo
188 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
191 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
193 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
194 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
197 /***********************************************************************
198 * MenuGetRosMenuItemInfo
200 * Get full information about a menu item
202 #define INITIAL_STRING_SIZE 32 /* in WCHARs */
204 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
208 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
210 /* There's already a buffer allocated */
211 Text
.Buffer
= ItemInfo
->dwTypeData
;
212 Text
.Length
= ItemInfo
->cch
* sizeof(WCHAR
);
213 Text
.MaximumLength
= (ItemInfo
->cch
< INITIAL_STRING_SIZE
? INITIAL_STRING_SIZE
214 : ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
218 Text
.Buffer
= HeapAlloc(GetProcessHeap(), 0, INITIAL_STRING_SIZE
* sizeof(WCHAR
));
219 if (NULL
== Text
.Buffer
)
224 Text
.MaximumLength
= INITIAL_STRING_SIZE
* sizeof(WCHAR
);
225 ItemInfo
->cch
= INITIAL_STRING_SIZE
- 1;
227 ItemInfo
->dwTypeData
= (LPWSTR
) &Text
;
229 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
230 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
232 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
234 if (NULL
!= Text
.Buffer
)
236 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
237 ItemInfo
->dwTypeData
= NULL
;
243 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
))
245 /* We have a string... */
246 if (Text
.MaximumLength
< (ItemInfo
->cch
+ 1) * sizeof(WCHAR
))
248 /* ...but we didn't allocate enough memory. Let's try again */
249 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
250 Text
.Buffer
= HeapAlloc(GetProcessHeap(), 0, (ItemInfo
->cch
+ 1) * sizeof(WCHAR
));
251 if (NULL
== Text
.Buffer
)
253 ItemInfo
->dwTypeData
= NULL
;
257 Text
.Length
= (ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
258 Text
.MaximumLength
= (ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
260 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
262 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
263 ItemInfo
->dwTypeData
= NULL
;
270 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
))
272 ItemInfo
->dwTypeData
= Text
.Buffer
;
273 ItemInfo
->cch
= Text
.Length
/ sizeof(WCHAR
);
274 Text
.Buffer
[ItemInfo
->cch
] = L
'\0';
278 /* Not a string, clean up the buffer */
279 if (NULL
!= Text
.Buffer
)
281 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
288 /***********************************************************************
289 * MenuSetRosMenuItemInfo
291 * Set full information about a menu item
294 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
300 StringVal
= (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
);
303 Text
.Buffer
= ItemInfo
->dwTypeData
;
304 Text
.Length
= wcslen(Text
.Buffer
) * sizeof(WCHAR
);
305 Text
.MaximumLength
= Text
.Length
+ sizeof(WCHAR
);
306 ItemInfo
->dwTypeData
= (LPWSTR
) &Text
;
308 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
309 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
311 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
315 ItemInfo
->dwTypeData
= Text
.Buffer
;
321 /***********************************************************************
322 * MenuCleanupRosMenuItemInfo
324 * Cleanup after use of MenuGet/SetRosMenuItemInfo
327 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
329 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
331 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
332 ItemInfo
->dwTypeData
= NULL
;
337 /***********************************************************************
338 * MenuGetAllRosMenuItemInfo
340 * Get full information about all menu items
343 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
347 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
352 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
353 if (NULL
== *ItemInfo
)
358 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
361 /***********************************************************************
362 * MenuCleanupAllRosMenuItemInfo
364 * Cleanup after use of MenuGetAllRosMenuItemInfo
367 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
369 HeapFree(GetProcessHeap(), 0, ItemInfo
);
372 /***********************************************************************
375 * Draw a single menu item.
378 MenuDrawMenuItem(HWND Wnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC Dc
,
379 PROSMENUITEMINFO Item
, UINT Height
, BOOL MenuBar
, UINT Action
)
384 if (0 != (Item
->fType
& MF_SYSMENU
))
387 if( !IsIconic(hwnd
) ) {
388 if (TWEAK_WineLook
> WIN31_LOOK
)
389 NC_DrawSysButton95( hwnd
, hdc
,
391 (MF_HILITE
| MF_MOUSESELECT
) );
393 NC_DrawSysButton( hwnd
, hdc
,
395 (MF_HILITE
| MF_MOUSESELECT
) );
402 if (0 != (Item
->fType
& MF_OWNERDRAW
))
405 ** Experimentation under Windows reveals that an owner-drawn
406 ** menu is given the rectangle which includes the space it requested
407 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
408 ** and a popup-menu arrow. This is the value of lpitem->rect.
409 ** Windows will leave all drawing to the application except for
410 ** the popup-menu arrow. Windows always draws that itself, after
411 ** the menu owner has finished drawing.
415 dis
.CtlType
= ODT_MENU
;
417 dis
.itemID
= Item
->wID
;
418 dis
.itemData
= (DWORD
)Item
->dwItemData
;
420 if (0 != (Item
->fState
& MF_CHECKED
))
422 dis
.itemState
|= ODS_CHECKED
;
424 if (0 != (Item
->fState
& MF_GRAYED
))
426 dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
428 if (0 != (Item
->fState
& MF_HILITE
))
430 dis
.itemState
|= ODS_SELECTED
;
432 dis
.itemAction
= Action
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
433 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
435 dis
.rcItem
= Item
->Rect
;
436 DPRINT("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
437 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner
,
438 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
439 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
441 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
442 /* Fall through to draw popup-menu arrow */
445 DPRINT("rect={%ld,%ld,%ld,%ld}\n", Item
->rect
.left
, Item
->rect
.top
,
446 Item
->rect
.right
, Item
->rect
.bottom
);
448 if (MenuBar
&& 0 != (Item
->fType
& MF_SEPARATOR
))
455 if (0 == (Item
->fType
& MF_OWNERDRAW
))
457 if (Item
->fState
& MF_HILITE
)
461 DrawEdge(Dc
, &Rect
, BDR_SUNKENOUTER
, BF_RECT
);
465 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
470 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_MENU
));
474 SetBkMode(Dc
, TRANSPARENT
);
476 if (0 == (Item
->fType
& MF_OWNERDRAW
))
478 /* vertical separator */
479 if (! MenuBar
&& 0 != (Item
->fType
& MF_MENUBARBREAK
))
483 rc
.bottom
= Height
- 3;
484 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
487 /* horizontal separator */
488 if (0 != (Item
->fType
& MF_SEPARATOR
))
493 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
494 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_TOP
);
502 if (0 != (Item
->fState
& MF_HILITE
))
506 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
507 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
511 if (0 != (Item
->fState
& MF_GRAYED
))
513 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
517 SetTextColor(Dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
519 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
524 if (0 != (Item
->fState
& MF_GRAYED
))
526 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
530 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
532 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
536 /* helper lines for debugging */
537 FrameRect(Dc
, &Rect
, GetStockObject(BLACK_BRUSH
));
538 SelectObject(Dc
, SYSCOLOR_GetPen(COLOR_WINDOWFRAME
));
539 MoveToEx(Dc
, Rect
.left
, (Rect
.top
+ Rect
.bottom
) / 2, NULL
);
540 LineTo(Dc
, Rect
.right
, (Rect
.top
+ Rect
.bottom
) / 2);
545 INT y
= Rect
.top
+ Rect
.bottom
;
546 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
547 UINT CheckBitmapHeight
= GetSystemMetrics(SM_CYMENUCHECK
);
549 if (0 == (Item
->fType
& MF_OWNERDRAW
))
551 /* Draw the check mark
554 * Custom checkmark bitmaps are monochrome but not always 1bpp.
557 HBITMAP bm
= 0 != (Item
->fState
& MF_CHECKED
) ? Item
->hCheckBit
: Item
->hUnCheckBit
;
558 if (NULL
!= bm
) /* we have a custom bitmap */
560 HDC DcMem
= CreateCompatibleDC(Dc
);
561 SelectObject(DcMem
, bm
);
562 BitBlt(Dc
, Rect
.left
, (y
- CheckBitmapHeight
) / 2,
563 CheckBitmapWidth
, CheckBitmapHeight
,
564 DcMem
, 0, 0, SRCCOPY
);
567 else if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
569 if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
573 HBITMAP bm
= CreateBitmap(CheckBitmapWidth
, CheckBitmapHeight
, 1, 1, NULL
);
574 HDC DcMem
= CreateCompatibleDC(Dc
);
575 SelectObject(DcMem
, bm
);
576 SetRect( &r
, 0, 0, CheckBitmapWidth
, CheckBitmapHeight
);
577 DrawFrameControl(DcMem
, &r
, DFC_MENU
,
578 0 != (Item
->fType
& MFT_RADIOCHECK
) ?
579 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
580 BitBlt(Dc
, Rect
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
581 DcMem
, 0, 0, SRCCOPY
);
588 /* Draw the popup-menu arrow */
589 if (lpitem
->fType
& MF_POPUP
)
591 HDC hdcMem
= CreateCompatibleDC( hdc
);
594 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
595 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
596 (y
- arrow_bitmap_height
) / 2,
597 arrow_bitmap_width
, arrow_bitmap_height
,
598 hdcMem
, 0, 0, SRCCOPY
);
599 SelectObject( hdcMem
, hOrigBitmap
);
604 Rect
.left
+= CheckBitmapWidth
;
605 Rect
.right
-= ArrowBitmapWidth
;
608 /* Done for owner-drawn */
609 if (0 != (Item
->fType
& MF_OWNERDRAW
))
614 /* Draw the item text or bitmap */
615 if (IS_BITMAP_ITEM(Item
->fType
))
618 MENU_DrawBitmapItem( hdc
, lpitem
, &rect
, menuBar
);
622 /* No bitmap - process text if present */
623 else if (IS_STRING_ITEM(Item
->fType
))
626 HFONT FontOld
= NULL
;
628 UINT uFormat
= MenuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
629 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
631 if (0 != (Item
->fState
& MFS_DEFAULT
))
633 FontOld
= SelectObject(Dc
, hMenuFontBold
);
638 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
639 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
642 Text
= (PWCHAR
) Item
->dwTypeData
;
643 for (i
= 0; L
'\0' != Text
[i
]; i
++)
645 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
651 if (0 != (Item
->fState
& MF_GRAYED
))
653 if (0 == (Item
->fState
& MF_HILITE
))
655 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
656 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
657 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
658 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
660 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
663 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
665 /* paint the shortcut text */
666 if (! MenuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
668 if (L
'\t' == Text
[i
])
670 Rect
.left
= Item
->XTab
;
671 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
675 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
678 if (0 != (Item
->fState
& MF_GRAYED
))
680 if (0 == (Item
->fState
& MF_HILITE
))
682 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
683 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
684 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
685 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
687 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
689 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
694 SelectObject(Dc
, FontOld
);
699 /***********************************************************************
702 * Paint a popup menu.
705 MenuDrawPopupMenu(HWND Wnd
, HDC Dc
, HMENU Menu
)
707 HBRUSH PrevBrush
= NULL
;
710 ROSMENUINFO MenuInfo
;
711 ROSMENUITEMINFO ItemInfo
;
714 DPRINT("wnd=%x dc=%x menu=%x\n", Wnd
, Dc
, Menu
);
716 GetClientRect(Wnd
, &Rect
);
718 if (NULL
!= (PrevBrush
= SelectObject(Dc
, GetSysColorBrush(COLOR_MENU
)))
719 && NULL
!= SelectObject(Dc
, hMenuFont
))
721 Rectangle(Dc
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
723 PrevPen
= SelectObject(Dc
, GetStockObject(NULL_PEN
));
726 DrawEdge(Dc
, &Rect
, EDGE_RAISED
, BF_RECT
);
728 /* draw menu items */
730 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 != MenuInfo
.MenuItemCount
)
732 MenuInitRosMenuItemInfo(&ItemInfo
);
734 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
736 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
738 MenuDrawMenuItem(Wnd
, &MenuInfo
, MenuInfo
.WndOwner
, Dc
, &ItemInfo
,
739 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
746 SelectObject(Dc
, PrevBrush
);
751 static LRESULT WINAPI
752 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
754 DPRINT("hwnd=%x msg=0x%04x wp=0x%04x lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
760 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
761 SetWindowLongW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
765 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
766 return MA_NOACTIVATE
;
771 BeginPaint(Wnd
, &ps
);
772 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongW(Wnd
, 0));
781 /* zero out global pointer in case resident popup window was destroyed. */
791 if (0 == GetWindowLongW(Wnd
, 0))
793 OutputDebugStringA("no menu to display\n");
798 SetWindowLongW(Wnd
, 0, 0);
802 case MM_SETMENUHANDLE
:
803 SetWindowLongW(Wnd
, 0, wParam
);
806 case MM_GETMENUHANDLE
:
807 return GetWindowLongW(Wnd
, 0);
810 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
816 /**********************************************************************
817 * MENUEX_ParseResource
819 * Parse an extended menu resource and add items to the menu.
820 * Return a pointer to the end of the resource.
822 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
824 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
832 mii
.cbSize
= sizeof(mii
);
833 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
834 mii
.fType
= GET_DWORD(res
);
835 res
+= sizeof(DWORD
);
836 mii
.fState
= GET_DWORD(res
);
837 res
+= sizeof(DWORD
);
838 mii
.wID
= GET_DWORD(res
);
839 res
+= sizeof(DWORD
);
840 resinfo
= GET_WORD(res
);
842 /* Align the text on a word boundary. */
843 res
+= (~((int)res
- 1)) & 1;
844 mii
.dwTypeData
= (LPWSTR
) res
;
845 res
+= (1 + wcslen(mii
.dwTypeData
)) * sizeof(WCHAR
);
846 /* Align the following fields on a dword boundary. */
847 res
+= (~((int)res
- 1)) & 3;
849 if (resinfo
& 1) /* Pop-up? */
851 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
852 res
+= sizeof(DWORD
);
853 mii
.hSubMenu
= CreatePopupMenu();
856 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
858 DestroyMenu(mii
.hSubMenu
);
861 mii
.fMask
|= MIIM_SUBMENU
;
862 mii
.fType
|= MF_POPUP
;
864 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
866 DbgPrint("WARN: Converting NULL menu item %04x, type %04x to SEPARATOR\n",
868 mii
.fType
|= MF_SEPARATOR
;
870 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
872 while (!(resinfo
& MF_END
));
877 /**********************************************************************
880 * Parse a standard menu resource and add items to the menu.
881 * Return a pointer to the end of the resource.
883 * NOTE: flags is equivalent to the mtOption field
885 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
894 flags
= GET_WORD(res
);
896 /* remove MF_END flag before passing it to AppendMenu()! */
897 end
= (flags
& MF_END
);
898 if(end
) flags
^= MF_END
;
901 if(!(flags
& MF_POPUP
))
908 res
+= strlen(str
) + 1;
910 res
+= (wcslen((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
911 if (flags
& MF_POPUP
)
913 hSubMenu
= CreatePopupMenu();
914 if(!hSubMenu
) return NULL
;
915 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
918 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
920 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
922 else /* Not a popup */
925 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
927 AppendMenuW(hMenu
, flags
, id
,
928 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
937 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
941 hUser32
= GetModuleHandleW(L
"USER32");
942 Result
= (LRESULT
)LoadMenuW(hUser32
, L
"SYSMENU");
943 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
950 NONCLIENTMETRICSW ncm
;
952 /* get the menu font */
953 if(!hMenuFont
|| !hMenuFontBold
)
955 ncm
.cbSize
= sizeof(ncm
);
956 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
958 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
962 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
963 if(hMenuFont
== NULL
)
965 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
969 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
970 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
971 if(hMenuFontBold
== NULL
)
973 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
983 MeasureMenuItem(HWND hWnd
, HMENU mnu
, HDC hDC
, PROSMENUITEMINFO mii
, LPWSTR str
)
986 MEASUREITEMSTRUCT mis
;
989 if(mii
->fType
& MFT_OWNERDRAW
)
991 /* send WM_MEASUREITEM message to window */
992 mis
.CtlType
= ODT_MENU
;
994 mis
.itemID
= mii
->wID
;
997 mis
.itemData
= mii
->dwItemData
;
998 res
= (BOOL
)SendMessageW(hWnd
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1001 mii
->Rect
.right
= mii
->Rect
.left
+ mis
.itemWidth
;
1002 mii
->Rect
.bottom
= mii
->Rect
.top
+ mis
.itemHeight
;
1006 /* FIXME calculate size internally assuming the menu item is empty */
1007 mii
->Rect
.right
= mii
->Rect
.left
+ 1;
1008 mii
->Rect
.bottom
= mii
->Rect
.top
+ 1;
1014 GetTextExtentPoint32W(hDC
, str
, mii
->cch
, &sz
);
1015 /* FIXME calculate the size of the menu item */
1016 mii
->Rect
.right
= mii
->Rect
.left
+ sz
.cx
+ 6;
1017 mii
->Rect
.bottom
= mii
->Rect
.top
+ max(sz
.cy
, GetSystemMetrics(SM_CYMENU
));
1023 DrawMenuItem(HWND hWnd
, HMENU mnu
, HDC hDC
, PROSMENUITEMINFO mii
, LPWSTR str
)
1028 if(mii
->fType
& MFT_OWNERDRAW
)
1030 /* send WM_DRAWITEM message to window */
1031 dis
.CtlType
= ODT_MENU
;
1033 dis
.itemID
= mii
->wID
;
1034 dis
.itemAction
= ODA_DRAWENTIRE
; /* FIXME */
1035 dis
.itemState
= 0; /* FIXME */
1036 dis
.hwndItem
= (HWND
)mnu
;
1038 RtlCopyMemory(&dis
.rcItem
, &mii
->Rect
, sizeof(RECT
));
1039 dis
.itemData
= mii
->dwItemData
;
1040 res
= (BOOL
)SendMessageW(hWnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1045 /* FIXME draw the menu item */
1046 SetTextColor(hDC
, COLOR_MENUTEXT
);
1047 SetBkMode(hDC
, TRANSPARENT
);
1048 DrawTextW(hDC
, str
, mii
->cch
, &mii
->Rect
, DT_SINGLELINE
| DT_VCENTER
| DT_CENTER
);
1054 /***********************************************************************
1057 * Calculate the size of the menu item and store it in ItemInfo->rect.
1059 static void FASTCALL
1060 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, HWND WndOwner
,
1061 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1064 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1066 DPRINT("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1068 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1070 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1073 ** Experimentation under Windows reveals that an owner-drawn
1074 ** menu is expected to return the size of the content part of
1075 ** the menu item, not including the checkmark nor the submenu
1076 ** arrow. Windows adds those values itself and returns the
1077 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1079 MEASUREITEMSTRUCT mis
;
1080 mis
.CtlType
= ODT_MENU
;
1082 mis
.itemID
= ItemInfo
->wID
;
1083 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1086 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1087 ItemInfo
->Rect
.right
+= mis
.itemWidth
;
1091 ItemInfo
->Rect
.right
+= MENU_BAR_ITEMS_SPACE
;
1093 /* under at least win95 you seem to be given a standard
1094 height for the menu and the height value is ignored */
1096 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENU
) - 1;
1100 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1103 DPRINT("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1104 /* Fall through to get check/arrow width calculation. */
1107 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1109 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1115 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1116 if (0 != (ItemInfo
->fType
& MF_POPUP
))
1118 ItemInfo
->Rect
.right
+= ArrowBitmapWidth
;
1122 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1127 if (IS_BITMAP_ITEM(ItemInfo
->fType
))
1132 MENU_GetBitmapItemSize( (int)lpitem
->text
, lpitem
->dwItemData
, &size
);
1133 lpitem
->rect
.right
+= size
.cx
;
1134 lpitem
->rect
.bottom
+= size
.cy
;
1136 /* Leave space for the sunken border */
1137 lpitem
->rect
.right
+= 2;
1138 lpitem
->rect
.bottom
+= 2;
1142 /* it must be a text item - unless it's the system menu */
1143 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && IS_STRING_ITEM(ItemInfo
->fType
))
1147 GetTextExtentPoint32W(Dc
, (LPWSTR
) ItemInfo
->dwTypeData
,
1148 wcslen((LPWSTR
) ItemInfo
->dwTypeData
), &Size
);
1150 ItemInfo
->Rect
.right
+= Size
.cx
;
1151 ItemInfo
->Rect
.bottom
+= max(Size
.cy
, GetSystemMetrics(SM_CYMENU
) - 1);
1156 ItemInfo
->Rect
.right
+= MENU_BAR_ITEMS_SPACE
;
1158 else if ((p
= wcschr((LPWSTR
) ItemInfo
->dwTypeData
, L
'\t' )) != NULL
)
1160 /* Item contains a tab (only meaningful in popup menus) */
1161 GetTextExtentPoint32W(Dc
, (LPWSTR
) ItemInfo
->dwTypeData
,
1162 (int)(p
- (LPWSTR
) ItemInfo
->dwTypeData
), &Size
);
1163 ItemInfo
->XTab
= CheckBitmapWidth
+ MENU_TAB_SPACE
+ Size
.cx
;
1164 ItemInfo
->Rect
.right
+= MENU_TAB_SPACE
;
1168 if (NULL
!= wcschr((LPWSTR
) ItemInfo
->dwTypeData
, L
'\b'))
1170 ItemInfo
->Rect
.right
+= MENU_TAB_SPACE
;
1172 ItemInfo
->XTab
= ItemInfo
->Rect
.right
- CheckBitmapWidth
1177 DPRINT("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1180 /***********************************************************************
1181 * MenuPopupMenuCalcSize
1183 * Calculate the size of a popup menu.
1185 static void FASTCALL
1186 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1188 ROSMENUITEMINFO ItemInfo
;
1191 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1193 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1194 if (0 == MenuInfo
->MenuItemCount
)
1196 MenuSetRosMenuInfo(MenuInfo
);
1201 SelectObject(Dc
, hMenuFont
);
1206 MenuInitRosMenuItemInfo(&ItemInfo
);
1207 while (Start
< MenuInfo
->MenuItemCount
)
1212 MaxTab
= MaxTabWidth
= 0;
1214 /* Parse items until column break or end of menu */
1215 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1217 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1219 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1220 MenuSetRosMenuInfo(MenuInfo
);
1224 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1229 MenuCalcItemSize(Dc
, &ItemInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1230 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1232 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1233 MenuSetRosMenuInfo(MenuInfo
);
1237 if (0 != (ItemInfo
.fType
& MF_MENUBARBREAK
))
1241 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1242 OrgY
= ItemInfo
.Rect
.bottom
;
1243 if (IS_STRING_ITEM(ItemInfo
.fType
) && 0 != ItemInfo
.XTab
)
1245 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1246 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1250 /* Finish the column (set all items to the largest width found) */
1251 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1254 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1256 ItemInfo
.Rect
.right
= MaxX
;
1257 if (IS_STRING_ITEM(ItemInfo
.fType
) && 0 != ItemInfo
.XTab
)
1259 ItemInfo
.XTab
= MaxTab
;
1261 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1265 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1268 MenuInfo
->Width
= MaxX
;
1270 /* space for 3d border */
1271 MenuInfo
->Height
+= 2;
1272 MenuInfo
->Width
+= 2;
1274 ReleaseDC(NULL
, Dc
);
1275 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1276 MenuSetRosMenuInfo(MenuInfo
);
1279 #if 0 /* Not used yet */
1280 /***********************************************************************
1281 * MenuMenuBarCalcSize
1283 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1284 * height is off by 1 pixel which causes lengthy window relocations when
1285 * active document window is maximized/restored.
1287 * Calculate the size of the menu bar.
1289 static void FASTCALL
1290 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1292 ROSMENUITEMINFO ItemInfo
;
1293 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1295 if (NULL
== Rect
|| NULL
== MenuInfo
)
1299 if (0 == MenuInfo
->MenuItemCount
)
1304 DPRINT("left=%ld top=%ld right=%ld bottom=%ld\n",
1305 Rrect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1306 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1307 MenuInfo
->Height
= 0;
1308 MaxY
= Rect
->top
+ 1;
1311 MenuInitRosMenuItemInfo(&ItemInfo
);
1312 while (Start
< MenuInfo
->MenuItemCount
)
1314 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1316 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1322 /* Parse items until line break or end of menu */
1323 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1325 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1330 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1335 DPRINT("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1336 MenuCalcItemSize(Dc
, &ItemInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1337 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1339 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1343 if (ItemInfo
.Rect
.right
> Rect
->right
)
1351 ItemInfo
.Rect
.right
= Rect
->right
;
1354 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1355 OrgX
= ItemInfo
.Rect
.right
;
1356 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1358 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1360 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1366 /* Finish the line (set all items to the largest height found) */
1369 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1371 ItemInfo
.Rect
.bottom
= MaxY
;
1372 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1378 Rect
->bottom
= MaxY
;
1379 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1380 MenuSetRosMenuInfo(MenuInfo
);
1384 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1385 /* the last item (if several lines, only move the last line) */
1386 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1388 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1391 OrgY
= ItemInfo
.Rect
.top
;
1393 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1399 if (ItemInfo
.Rect
.top
!= OrgY
)
1401 break; /* Other line */
1403 if (OrgX
<= ItemInfo
.Rect
.right
)
1405 break; /* Too far right already */
1407 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1408 ItemInfo
.Rect
.right
= OrgX
;
1409 OrgX
= ItemInfo
.Rect
.left
;
1410 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1411 if (HelpPos
+ 1 <= i
&&
1412 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1414 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1420 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1426 MenuDrawMenuBar(HDC hDC
, LPRECT Rect
, HWND hWnd
, BOOL Draw
)
1432 DWORD BufSize
, Items
, Items2
, hItems
;
1433 ROSMENUITEMINFO
*mii
;
1435 SETMENUITEMRECT smir
;
1439 mnu
= GetMenu(hWnd
); /* Fixme - pass menu handle as parameter */
1440 /* get menu item list size */
1441 BufSize
= NtUserBuildMenuItemList(mnu
, (VOID
*)1, 0, 0);
1444 hHeap
= GetProcessHeap();
1445 hBuf
= HeapAlloc(hHeap
, 0, BufSize
);
1449 /* copy menu items into buffer */
1450 Items
= Items2
= NtUserBuildMenuItemList(mnu
, Buf
, BufSize
, 0);
1454 bottom
= line
= Rect
->top
;
1455 smir
.fByPosition
= TRUE
;
1457 /* calculate menu item rectangles */
1462 mii
= (PROSMENUITEMINFO
)Buf
;
1463 Buf
+= sizeof(ROSMENUITEMINFO
);
1466 str
= (LPWSTR
)mii
->dwTypeData
;
1472 mii
->Rect
.left
= omir
.right
+ 1;
1473 mii
->Rect
.top
= omir
.top
;
1474 mii
->Rect
.right
+= mii
->Rect
.left
;
1475 mii
->Rect
.bottom
+= mii
->Rect
.top
;
1479 mii
->Rect
.left
= Rect
->left
;
1480 mii
->Rect
.top
= Rect
->top
;
1482 if((mii
->fType
& MFT_RIGHTJUSTIFY
) && !milist
)
1484 milist
= mih
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, Items
* sizeof(PROSMENUITEMINFO
));
1488 MeasureMenuItem(hWnd
, mnu
, hDC
, mii
, str
);
1490 if((mii
->Rect
.right
> Rect
->right
) || (mii
->fType
& (MFT_MENUBREAK
| MFT_MENUBARBREAK
)))
1492 mii
->Rect
.right
-= (mii
->Rect
.left
- Rect
->left
);
1493 mii
->Rect
.left
= Rect
->left
;
1494 mii
->Rect
.top
+= line
;
1495 mii
->Rect
.bottom
+= line
;
1496 line
= mii
->Rect
.bottom
- mii
->Rect
.top
;
1501 smir
.rcRect
= mii
->Rect
;
1502 NtUserSetMenuItemRect(mnu
, &smir
);
1510 bottom
= max(bottom
, mii
->Rect
.bottom
);
1511 line
= max(line
, mii
->Rect
.bottom
- mii
->Rect
.top
);
1515 /* align help menus to the right */
1521 smir
.uItem
= Items2
- 1;
1525 PROSMENUITEMINFO omii
;
1528 mii
= (PROSMENUITEMINFO
)(*(--mih
));
1530 if(omii
&& ((mii
->Rect
.right
> x
) || (omii
->fType
& (MFT_MENUBREAK
| MFT_MENUBARBREAK
))))
1535 wd
= (mii
->Rect
.right
- mii
->Rect
.left
);
1536 mii
->Rect
.right
= x
- 1;
1537 mii
->Rect
.left
= mii
->Rect
.right
- wd
;
1540 smir
.rcRect
= mii
->Rect
;
1542 NtUserSetMenuItemRect(mnu
, &smir
);
1549 HeapFree(GetProcessHeap(), 0, milist
);
1551 bottom
= max(bottom
, Rect
->top
+ GetSystemMetrics(SM_CYMENU
));
1552 if(bottom
- Rect
->top
> 0)
1554 NtUserSetMenuBarHeight(mnu
, bottom
- Rect
->top
);
1559 bottom
= Rect
->bottom
;
1560 FillRect(hDC
, Rect
, GetSysColorBrush(COLOR_MENU
));
1562 /* draw menu items */
1565 mii
= (PROSMENUITEMINFO
)Buf
;
1566 Buf
+= sizeof(ROSMENUITEMINFO
);
1569 str
= (LPWSTR
)mii
->dwTypeData
;
1573 /* DbgPrint("Draw menu item %ws at (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
1574 DrawMenuItem(hWnd
, mnu
, hDC
, mii
, str
);
1579 HeapFree(hHeap
, 0, hBuf
);
1582 return max(bottom
- Rect
->top
, GetSystemMetrics(SM_CYMENU
));
1585 /***********************************************************************
1588 static BOOL FASTCALL
1589 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1591 DPRINT("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1595 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1596 if (0 == (Flags
& TPM_NONOTIFY
))
1598 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1601 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1603 if (0 == (Flags
& TPM_NONOTIFY
))
1605 ROSMENUINFO MenuInfo
;
1607 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1609 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 == MenuInfo
.Height
)
1611 /* app changed/recreated menu bar entries in WM_INITMENU
1612 Recalculate menu sizes else clicks will not work */
1613 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1614 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1623 /***********************************************************************
1626 * Display a popup menu.
1628 static BOOL FASTCALL
1629 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1630 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1632 ROSMENUINFO MenuInfo
;
1633 ROSMENUITEMINFO ItemInfo
;
1636 DPRINT("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1637 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1639 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1644 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1646 MenuInitRosMenuItemInfo(&ItemInfo
);
1647 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1649 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1650 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1652 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1653 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1656 /* store the owner for DrawItem */
1657 MenuInfo
.WndOwner
= WndOwner
;
1658 MenuSetRosMenuInfo(&MenuInfo
);
1660 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1662 /* adjust popup menu pos so that it fits within the desktop */
1664 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1665 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1667 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1671 X
-= Width
- XAnchor
;
1673 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1675 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1683 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1687 Y
-= Height
+ YAnchor
;
1689 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1691 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
1700 /* NOTE: In Windows, top menu popup is not owned. */
1701 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
1702 WS_POPUP
, X
, Y
, Width
, Height
,
1703 WndOwner
, 0, (HINSTANCE
) GetWindowLongW(WndOwner
, GWL_HINSTANCE
),
1704 (LPVOID
) MenuInfo
.Self
);
1705 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
1709 if (NULL
== TopPopup
)
1711 TopPopup
= MenuInfo
.Wnd
;
1714 /* Display the window */
1715 SetWindowPos(MenuInfo
.Wnd
, HWND_TOP
, 0, 0, 0, 0,
1716 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1717 UpdateWindow(MenuInfo
.Wnd
);
1722 /***********************************************************************
1725 * Find a Sub menu. Return the position of the submenu, and modifies
1726 * *hmenu in case it is found in another sub-menu.
1727 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
1729 static UINT FASTCALL
1730 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
1732 ROSMENUINFO MenuInfo
;
1733 ROSMENUITEMINFO ItemInfo
;
1738 if ((HMENU
) 0xffff == *Menu
1739 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
1741 return NO_SELECTED_ITEM
;
1744 MenuInitRosMenuItemInfo(&ItemInfo
);
1745 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1747 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1749 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1750 return NO_SELECTED_ITEM
;
1752 if (0 == (ItemInfo
.fType
& MF_POPUP
))
1756 if (ItemInfo
.hSubMenu
== SubTarget
)
1758 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1761 SubMenu
= ItemInfo
.hSubMenu
;
1762 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
1763 if (NO_SELECTED_ITEM
!= Pos
)
1769 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1771 return NO_SELECTED_ITEM
;
1774 /***********************************************************************
1777 static void FASTCALL
1778 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
1779 BOOL SendMenuSelect
, HMENU TopMenu
)
1782 ROSMENUITEMINFO ItemInfo
;
1783 ROSMENUINFO TopMenuInfo
;
1786 DPRINT("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
1788 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
1793 if (MenuInfo
->FocusedItem
== Index
)
1798 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
1800 Dc
= GetDC(MenuInfo
->Wnd
);
1804 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1807 if (NULL
== TopPopup
)
1809 TopPopup
= MenuInfo
->Wnd
;
1812 SelectObject(Dc
, hMenuFont
);
1813 MenuInitRosMenuItemInfo(&ItemInfo
);
1815 /* Clear previous highlighted item */
1816 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1818 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1820 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1821 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1823 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
1824 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1828 /* Highlight new item (if any) */
1829 MenuInfo
->FocusedItem
= Index
;
1830 MenuSetRosMenuInfo(MenuInfo
);
1831 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1833 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1835 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1837 ItemInfo
.fState
|= MF_HILITE
;
1838 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1839 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
1840 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1845 SendMessageW(WndOwner
, WM_MENUSELECT
,
1846 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
1847 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1848 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
1852 else if (SendMenuSelect
)
1854 if (NULL
!= TopMenu
)
1856 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
1857 if (NO_SELECTED_ITEM
!= Pos
)
1859 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
1860 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
1862 SendMessageW(WndOwner
, WM_MENUSELECT
,
1863 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1865 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1872 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1873 ReleaseDC(MenuInfo
->Wnd
, Dc
);
1876 /***********************************************************************
1879 * Moves currently selected item according to the Offset parameter.
1880 * If there is no selection then it should select the last item if
1881 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1883 static void FASTCALL
1884 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1887 ROSMENUITEMINFO ItemInfo
;
1889 DPRINT("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, offset
);
1891 MenuInitRosMenuItemInfo(&ItemInfo
);
1892 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1894 if (1 == MenuInfo
->MenuItemCount
)
1896 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1901 for (i
= MenuInfo
->FocusedItem
+ Offset
;
1902 0 <= i
&& i
< MenuInfo
->MenuItemCount
;
1905 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1906 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1908 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1909 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1916 for (i
= (0 < Offset
) ? 0 : MenuInfo
->MenuItemCount
- 1;
1917 0 <= i
&& i
< MenuInfo
->MenuItemCount
; i
+= Offset
)
1919 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1920 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1922 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1923 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1928 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1931 /***********************************************************************
1932 * MenuInitSysMenuPopup
1934 * Grey the appropriate items in System menu.
1936 static void FASTCALL
1937 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
)
1941 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1942 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1943 Gray
= 0 != (Style
& WS_MAXIMIZE
);
1944 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1945 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
1946 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1947 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
1948 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1949 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1950 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1951 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
1953 /* The menu item must keep its state if it's disabled */
1956 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
1960 /***********************************************************************
1963 * Display the sub-menu of the selected item of this menu.
1964 * Return the handle of the submenu, or menu if no submenu to display.
1966 static HMENU FASTCALL
1967 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
1969 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
1971 ROSMENUITEMINFO ItemInfo
;
1972 ROSMENUINFO SubMenuInfo
;
1976 DPRINT("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
1978 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
1980 return MenuInfo
->Self
;
1983 MenuInitRosMenuItemInfo(&ItemInfo
);
1984 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1986 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1987 return MenuInfo
->Self
;
1989 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
1991 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1992 return MenuInfo
->Self
;
1995 /* message must be sent before using item,
1996 because nearly everything may be changed by the application ! */
1998 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
1999 if (0 == (Flags
& TPM_NONOTIFY
))
2001 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2002 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2005 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2007 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2008 return MenuInfo
->Self
;
2010 Rect
= ItemInfo
.Rect
;
2012 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2013 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2015 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2017 Dc
= GetDC(MenuInfo
->Wnd
);
2021 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2024 SelectObject(Dc
, hMenuFont
);
2026 ItemInfo
.fState
|= MF_HILITE
;
2027 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2028 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2029 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2030 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2033 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2034 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2036 ItemInfo
.Rect
= Rect
;
2039 ItemInfo
.fState
|= MF_MOUSESELECT
;
2041 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2043 if (IS_SYSTEM_MENU(MenuInfo
))
2045 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
,
2046 GetWindowLongW(MenuInfo
->Wnd
, GWL_STYLE
),
2047 GetClassLongW(MenuInfo
->Wnd
, GCL_STYLE
));
2049 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2050 Rect
.top
= Rect
.bottom
;
2051 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2052 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2056 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2057 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2059 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2060 Rect
.top
+= ItemInfo
.Rect
.top
;
2061 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2062 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
;
2066 Rect
.left
+= ItemInfo
.Rect
.left
;
2067 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2068 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2069 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2073 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2074 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2075 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2077 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2080 Ret
= ItemInfo
.hSubMenu
;
2081 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2086 /***********************************************************************
2089 * Hide the sub-popup menus of this menu.
2091 static void FASTCALL
2092 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2094 ROSMENUINFO SubMenuInfo
;
2095 ROSMENUITEMINFO ItemInfo
;
2097 DPRINT("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2099 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2101 MenuInitRosMenuItemInfo(&ItemInfo
);
2102 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2103 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2104 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2106 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2109 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2110 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2111 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2113 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2114 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2115 DestroyWindow(SubMenuInfo
.Wnd
);
2116 SubMenuInfo
.Wnd
= NULL
;
2117 MenuSetRosMenuInfo(&SubMenuInfo
);
2122 /***********************************************************************
2123 * MenuSwitchTracking
2125 * Helper function for menu navigation routines.
2127 static void FASTCALL
2128 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2130 ROSMENUINFO TopMenuInfo
;
2132 DPRINT("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2134 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2135 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2136 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2138 /* both are top level menus (system and menu-bar) */
2139 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2140 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2141 Mt
->TopMenu
= PtMenuInfo
->Self
;
2145 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2148 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2151 /***********************************************************************
2152 * MenuExecFocusedItem
2154 * Execute a menu item (for instance when user pressed Enter).
2155 * Return the wID of the executed item. Otherwise, -1 indicating
2156 * that no menu item was executed;
2157 * Have to receive the flags for the TrackPopupMenu options to avoid
2158 * sending unwanted message.
2162 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2164 ROSMENUITEMINFO ItemInfo
;
2167 DPRINT("%p menu=%p\n", Mt
, MenuInfo
);
2169 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2174 MenuInitRosMenuItemInfo(&ItemInfo
);
2175 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2177 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2181 DPRINT("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2183 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2185 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2186 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2188 /* If TPM_RETURNCMD is set you return the id, but
2189 do not send a message to the owner */
2190 if (0 == (Flags
& TPM_RETURNCMD
))
2192 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2194 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2195 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2199 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2203 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2209 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2215 /***********************************************************************
2218 * Return TRUE if we can go on with menu tracking.
2220 static BOOL FASTCALL
2221 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2224 ROSMENUINFO MenuInfo
;
2225 ROSMENUITEMINFO Item
;
2227 DPRINT("%x PtMenu=%p\n", Mt
, PtMenu
);
2231 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2235 if (IS_SYSTEM_MENU(&MenuInfo
))
2241 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2243 MenuInitRosMenuItemInfo(&Item
);
2244 if (Index
< 0 || ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2246 MenuCleanupRosMenuItemInfo(&Item
);
2250 if (MenuInfo
.FocusedItem
!= Index
)
2252 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2255 /* If the popup menu is not already "popped" */
2256 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2258 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2261 MenuCleanupRosMenuItemInfo(&Item
);
2266 /* else the click was on the menu bar, finish the tracking */
2271 /***********************************************************************
2274 * Return the value of MenuExecFocusedItem if
2275 * the selected item was not a popup. Else open the popup.
2276 * A -1 return value indicates that we go on with menu tracking.
2280 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2283 ROSMENUINFO MenuInfo
;
2284 ROSMENUITEMINFO ItemInfo
;
2286 DPRINT("%p hmenu=%x\n", Mt
, PtMenu
);
2291 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2296 if (! IS_SYSTEM_MENU(&MenuInfo
))
2298 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2300 MenuInitRosMenuItemInfo(&ItemInfo
);
2301 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2302 MenuInfo
.FocusedItem
== Id
)
2304 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2306 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2307 return MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2309 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2311 /* If we are dealing with the top-level menu */
2312 /* and this is a click on an already "popped" item: */
2313 /* Stop the menu tracking and close the opened submenus */
2314 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2316 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2320 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2321 MenuInfo
.TimeToHide
= TRUE
;
2322 MenuSetRosMenuInfo(&MenuInfo
);
2328 /***********************************************************************
2331 * Walks menu chain trying to find a menu pt maps to.
2333 static HMENU FASTCALL
2334 MenuPtMenu(HMENU Menu
, POINT Pt
)
2336 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2337 ROSMENUINFO MenuInfo
;
2338 ROSMENUITEMINFO ItemInfo
;
2342 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2347 /* try subpopup first (if any) */
2348 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2350 MenuInitRosMenuItemInfo(&ItemInfo
);
2351 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2352 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2353 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2355 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2358 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2362 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2365 /* check the current window (avoiding WM_HITTEST) */
2366 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2367 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2369 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2374 else if (HTSYSMENU
== Ht
)
2376 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2378 else if (HTMENU
== Ht
)
2380 Ret
= GetMenu(MenuInfo
.Wnd
);
2386 /***********************************************************************
2389 * Return TRUE if we can go on with menu tracking.
2391 static BOOL FASTCALL
2392 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2395 ROSMENUINFO MenuInfo
;
2399 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2403 if (IS_SYSTEM_MENU(&MenuInfo
))
2409 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2414 Index
= NO_SELECTED_ITEM
;
2417 if (NO_SELECTED_ITEM
== Index
)
2419 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2420 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2422 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2426 else if (MenuInfo
.FocusedItem
!= Index
)
2428 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2429 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2435 /******************************************************************************
2437 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2439 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2442 PROSMENUITEMINFO MenuItems
;
2444 i
= MenuInfo
->FocusedItem
;
2445 if (NO_SELECTED_ITEM
== i
)
2450 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2452 return NO_SELECTED_ITEM
;
2455 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2457 if (0 != (MenuItems
[i
].fType
& MF_MENUBARBREAK
))
2463 return NO_SELECTED_ITEM
;
2466 /******************************************************************************
2468 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2470 static UINT FASTCALL
2471 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2474 PROSMENUITEMINFO MenuItems
;
2476 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2478 return NO_SELECTED_ITEM
;
2481 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2483 return NO_SELECTED_ITEM
;
2486 /* Find the start of the column */
2488 for (i
= MenuInfo
->FocusedItem
;
2489 0 != i
&& 0 == (MenuItems
[i
].fType
& MF_MENUBARBREAK
);
2497 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2498 return NO_SELECTED_ITEM
;
2501 for (--i
; 0 != i
; --i
)
2503 if (MenuItems
[i
].fType
& MF_MENUBARBREAK
)
2509 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2510 DPRINT("ret %d.\n", i
);
2515 /***********************************************************************
2518 * Return the handle of the selected sub-popup menu (if any).
2520 static HMENU FASTCALL
2521 MenuGetSubPopup(HMENU Menu
)
2523 ROSMENUINFO MenuInfo
;
2524 ROSMENUITEMINFO ItemInfo
;
2526 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2527 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2532 MenuInitRosMenuItemInfo(&ItemInfo
);
2533 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2535 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2538 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2540 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2541 return ItemInfo
.hSubMenu
;
2544 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2548 /***********************************************************************
2551 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2553 static LRESULT FASTCALL
2554 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2556 ROSMENUINFO TopMenuInfo
;
2557 ROSMENUINFO MenuInfo
;
2559 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2561 return (LRESULT
) FALSE
;
2564 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2565 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2567 MDINEXTMENU NextMenu
;
2572 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2573 NextMenu
.hmenuNext
= NULL
;
2574 NextMenu
.hwndNext
= NULL
;
2575 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2577 DPRINT("%p [%p] -> %p [%p]\n",
2578 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2580 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2582 DWORD Style
= GetWindowLongW(Mt
->OwnerWnd
, GWL_STYLE
);
2583 NewWnd
= Mt
->OwnerWnd
;
2584 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2586 /* switch to the menu bar */
2588 if (0 != (Style
& WS_CHILD
)
2589 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2596 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2600 Id
= MenuInfo
.MenuItemCount
- 1;
2603 else if (0 != (Style
& WS_SYSMENU
))
2605 /* switch to the system menu */
2606 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2613 else /* application returned a new menu to switch to */
2615 NewMenu
= NextMenu
.hmenuNext
;
2616 NewWnd
= NextMenu
.hwndNext
;
2618 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2620 DWORD Style
= GetWindowLongW(NewWnd
, GWL_STYLE
);
2622 if (0 != (Style
& WS_SYSMENU
)
2623 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2625 /* get the real system menu */
2626 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2628 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2630 /* FIXME: Not sure what to do here;
2631 * perhaps try to track NewMenu as a popup? */
2633 DPRINT(" -- got confused.\n");
2643 if (NewMenu
!= Mt
->TopMenu
)
2645 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2647 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2649 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2653 if (NewWnd
!= Mt
->OwnerWnd
)
2655 Mt
->OwnerWnd
= NewWnd
;
2656 SetCapture(Mt
->OwnerWnd
);
2659 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2660 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2662 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2671 /***********************************************************************
2674 * The idea is not to show the popup if the next input message is
2675 * going to hide it anyway.
2677 static BOOL FASTCALL
2678 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2682 Msg
.hwnd
= Mt
->OwnerWnd
;
2684 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2685 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2690 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2691 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2693 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2694 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2695 if (WM_KEYDOWN
== Msg
.message
2696 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2698 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2705 /* failures go through this */
2706 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2711 /***********************************************************************
2714 * Handle a VK_ESCAPE key event in a menu.
2716 static BOOL FASTCALL
2717 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2719 BOOL EndMenu
= TRUE
;
2720 ROSMENUINFO MenuInfo
;
2721 HMENU MenuTmp
, MenuPrev
;
2723 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2725 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2726 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2728 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2730 /* close topmost popup */
2731 while (MenuTmp
!= Mt
->CurrentMenu
)
2734 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2737 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2739 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
2741 Mt
->CurrentMenu
= MenuPrev
;
2749 /***********************************************************************
2752 * Handle a VK_LEFT key event in a menu.
2754 static void FASTCALL
2755 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2757 ROSMENUINFO MenuInfo
;
2758 ROSMENUINFO TopMenuInfo
;
2759 ROSMENUINFO PrevMenuInfo
;
2760 HMENU MenuTmp
, MenuPrev
;
2763 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2765 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2770 /* Try to move 1 column left (if possible) */
2771 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
2773 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2775 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
2780 /* close topmost popup */
2781 while (MenuTmp
!= Mt
->CurrentMenu
)
2784 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2787 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
2791 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
2792 Mt
->CurrentMenu
= MenuPrev
;
2794 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2798 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
2800 /* move menu bar selection if no more popups are left */
2802 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
2804 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
2807 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
2809 /* A sublevel menu was displayed - display the next one
2810 * unless there is another displacement coming up */
2812 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
))
2814 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
2821 /***********************************************************************
2824 * Handle a VK_RIGHT key event in a menu.
2826 static void FASTCALL
2827 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
2830 ROSMENUINFO MenuInfo
;
2831 ROSMENUINFO CurrentMenuInfo
;
2834 DPRINT("MenuKeyRight called, cur %p, top %p.\n",
2835 Mt
->CurrentMenu
, Mt
->TopMenu
);
2837 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
2841 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
2843 /* If already displaying a popup, try to display sub-popup */
2845 MenuTmp
= Mt
->CurrentMenu
;
2846 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
2848 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
2851 /* if subpopup was displayed then we are done */
2852 if (MenuTmp
!= Mt
->CurrentMenu
)
2858 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
2863 /* Check to see if there's another column */
2864 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
2866 DPRINT("Going to %d.\n", NextCol
);
2867 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2869 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
2874 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
2876 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2878 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
2879 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
2886 /* try to move to the next item */
2887 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
2889 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
2892 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
2894 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
))
2896 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
2903 /***********************************************************************
2906 * Find the menu item selected by a key press.
2907 * Return item id, -1 if none, -2 if we should close the menu.
2909 static UINT FASTCALL
2910 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2911 WCHAR Key
, BOOL ForceMenuChar
)
2913 ROSMENUINFO SysMenuInfo
;
2914 PROSMENUITEMINFO Items
, ItemInfo
;
2918 DPRINT("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
2920 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
2922 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
2924 MenuInfo
= &SysMenuInfo
;
2932 if (NULL
!= MenuInfo
)
2934 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
2938 if (! ForceMenuChar
)
2940 Key
= towupper(Key
);
2942 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
2944 if (IS_STRING_ITEM(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
2946 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
2949 p
= wcschr(p
+ 2, '&');
2951 while (NULL
!= p
&& L
'&' == p
[1]);
2952 if (NULL
!= p
&& (towupper(p
[1]) == Key
))
2960 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
2961 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
2962 if (2 == HIWORD(MenuChar
))
2964 return LOWORD(MenuChar
);
2966 if (1 == HIWORD(MenuChar
))
2975 /***********************************************************************
2978 * Menu tracking code.
2981 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
2982 HWND Wnd
, const RECT
*Rect
)
2985 ROSMENUINFO MenuInfo
;
2986 ROSMENUITEMINFO ItemInfo
;
2988 INT ExecutedMenuId
= -1;
2990 BOOL EnterIdleSent
= FALSE
;
2993 Mt
.CurrentMenu
= Menu
;
2999 DPRINT("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3000 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3001 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3004 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3009 if (0 != (Flags
& TPM_BUTTONDOWN
))
3011 /* Get the result in order to start the tracking or not */
3012 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3013 fEndMenu
= ! fRemove
;
3016 SetCapture(Mt
.OwnerWnd
);
3020 /* we have to keep the message in the queue until it's
3021 * clear that menu loop is not over yet. */
3025 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3027 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3031 /* remove the message from the queue */
3032 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3036 if (! EnterIdleSent
)
3038 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3039 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3040 EnterIdleSent
= TRUE
;
3041 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3047 /* check if EndMenu() tried to cancel us, by posting this message */
3048 if (WM_CANCELMODE
== Msg
.message
)
3050 /* we are now out of the loop */
3053 /* remove the message from the queue */
3054 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3056 /* break out of internal loop, ala ESCAPE */
3060 TranslateMessage(&Msg
);
3063 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3065 EnterIdleSent
= FALSE
;
3069 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3072 * Use the mouse coordinates in lParam instead of those in the MSG
3073 * struct to properly handle synthetic messages. They are already
3074 * in screen coordinates.
3076 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3077 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3079 /* Find a menu for this mouse event */
3080 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3084 /* no WM_NC... messages in captured state */
3086 case WM_RBUTTONDBLCLK
:
3087 case WM_RBUTTONDOWN
:
3088 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3093 case WM_LBUTTONDBLCLK
:
3094 case WM_LBUTTONDOWN
:
3095 /* If the message belongs to the menu, removes it from the queue */
3096 /* Else, end menu tracking */
3097 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3098 fEndMenu
= ! fRemove
;
3102 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3108 /* Check if a menu was selected by the mouse */
3111 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3113 /* End the loop if ExecutedMenuId is an item ID */
3114 /* or if the job was done (ExecutedMenuId = 0). */
3115 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3119 /* No menu was selected by the mouse */
3120 /* if the function was called by TrackPopupMenu, continue
3121 with the menu tracking. If not, stop it */
3122 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3129 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3133 } /* switch(Msg.message) - mouse */
3135 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3137 fRemove
= TRUE
; /* Keyboard messages are always removed */
3145 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3147 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3153 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3155 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3156 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3160 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3161 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3163 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3165 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3167 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3171 else /* otherwise try to move selection */
3173 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3179 MenuKeyLeft(&Mt
, Flags
);
3183 MenuKeyRight(&Mt
, Flags
);
3187 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3193 hi
.cbSize
= sizeof(HELPINFO
);
3194 hi
.iContextType
= HELPINFO_MENUITEM
;
3195 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3197 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3203 MenuInitRosMenuItemInfo(&ItemInfo
);
3204 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3205 MenuInfo
.FocusedItem
,
3208 hi
.iCtrlId
= ItemInfo
.wID
;
3214 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3217 hi
.hItemHandle
= Menu
;
3218 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3219 hi
.MousePos
= Msg
.pt
;
3220 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3227 break; /* WM_KEYDOWN */
3236 break; /* WM_SYSKEYDOWN */
3242 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3246 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3248 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3249 fEndMenu
= (ExecutedMenuId
!= -1);
3253 /* Hack to avoid control chars. */
3254 /* We will find a better way real soon... */
3255 if (Msg
.wParam
< 32)
3260 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3261 LOWORD(Msg
.wParam
), FALSE
);
3262 if ((UINT
) -2 == Pos
)
3266 else if ((UINT
) -1 == Pos
)
3272 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3273 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3274 fEndMenu
= (-1 != ExecutedMenuId
);
3278 } /* switch(msg.message) - kbd */
3282 DispatchMessageW(&Msg
);
3290 /* finally remove message from the queue */
3292 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3294 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3298 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3302 SetCapture(NULL
); /* release the capture */
3304 /* If dropdown is still painted and the close box is clicked on
3305 then the menu will be destroyed as part of the DispatchMessage above.
3306 This will then invalidate the menu handle in Mt.hTopMenu. We should
3307 check for this first. */
3308 if (IsMenu(Mt
.TopMenu
))
3310 if (IsWindow(Mt
.OwnerWnd
))
3312 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3314 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3316 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3318 DestroyWindow(MenuInfo
.Wnd
);
3319 MenuInfo
.Wnd
= NULL
;
3321 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3324 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3327 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3329 /* Reset the variable for hiding menu */
3330 MenuInfo
.TimeToHide
= FALSE
;
3331 MenuSetRosMenuInfo(&MenuInfo
);
3335 /* The return value is only used by TrackPopupMenu */
3336 return (-1 != ExecutedMenuId
) ? ExecutedMenuId
: 0;
3339 /***********************************************************************
3342 static BOOL FASTCALL
3343 MenuExitTracking(HWND Wnd
)
3345 DPRINT("hwnd=%p\n", hWnd
);
3347 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3354 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3356 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3357 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3359 DPRINT("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, pt
.x
, pt
.y
);
3363 /* map point to parent client coordinates */
3364 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3365 if (Parent
!= GetDesktopWindow())
3367 ScreenToClient(Parent
, &Pt
);
3370 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3371 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3372 MenuExitTracking(Wnd
);
3378 MenuTrackKbdMenuBar(HWND hWnd
, ULONG wParam
, ULONG Key
)
3382 /* FUNCTIONS *****************************************************************/
3385 MenuIsStringItem(ULONG TypeData)
3387 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3395 AppendMenuA(HMENU hMenu
,
3397 UINT_PTR uIDNewItem
,
3400 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3409 AppendMenuW(HMENU hMenu
,
3411 UINT_PTR uIDNewItem
,
3414 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3423 CheckMenuItem(HMENU hmenu
,
3427 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3435 CheckMenuRadioItem(HMENU hmenu
,
3452 return NtUserCreateMenu(FALSE
);
3460 CreatePopupMenu(VOID
)
3462 return NtUserCreateMenu(TRUE
);
3470 DeleteMenu(HMENU hMenu
,
3474 return NtUserDeleteMenu(hMenu
, uPosition
, uFlags
);
3482 DestroyMenu(HMENU hMenu
)
3484 return NtUserDestroyMenu(hMenu
);
3492 DrawMenuBar(HWND hWnd
)
3495 /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
3504 EnableMenuItem(HMENU hMenu
,
3508 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
3518 guii
.cbSize
= sizeof(GUITHREADINFO
);
3519 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
3521 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
3533 return NtUserGetMenu(hWnd
);
3541 GetMenuBarInfo(HWND hwnd
,
3546 return (BOOL
)NtUserGetMenuBarInfo(hwnd
, idObject
, idItem
, pmbi
);
3554 GetMenuCheckMarkDimensions(VOID
)
3556 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
3557 GetSystemMetrics(SM_CYMENUCHECK
)));
3565 GetMenuDefaultItem(HMENU hMenu
,
3569 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
3577 GetMenuInfo(HMENU hmenu
,
3583 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
3586 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
3587 mi
.cbSize
= sizeof(MENUINFO
);
3588 mi
.fMask
= lpcmi
->fMask
;
3590 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
3592 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
3601 GetMenuItemCount(HMENU Menu
)
3603 ROSMENUINFO MenuInfo
;
3605 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
3613 GetMenuItemID(HMENU hMenu
,
3616 ROSMENUITEMINFO mii
;
3618 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3619 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
3621 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
3626 if (NULL
!= mii
.hSubMenu
)
3647 LPMENUITEMINFOA lpmii
)
3663 LPMENUITEMINFOW lpmii
)
3674 GetMenuItemRect(HWND hWnd
,
3694 ROSMENUINFO MenuInfo
;
3695 ROSMENUITEMINFO mii
;
3697 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3698 mii
.fMask
= MIIM_STATE
| MIIM_TYPE
| MIIM_SUBMENU
;
3701 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
3706 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
3710 nSubItems
= MenuInfo
.MenuItemCount
;
3712 /* FIXME - ported from wine, does that work (0xff)? */
3713 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
3714 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
3716 return (UINT
)-1; /* Invalid submenu */
3719 /* FIXME - ported from wine, does that work? */
3720 return (mii
.fType
| mii
.fState
);
3772 mi
.cbSize
= sizeof(MENUITEMINFOW
);
3773 mi
.fMask
= MIIM_SUBMENU
;
3775 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
3777 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
3794 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
3796 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
3811 return NtUserHiliteMenuItem(hwnd
, hmenu
, uItemHilite
, uHilite
);
3824 UINT_PTR uIDNewItem
,
3828 mii
.cbSize
= sizeof(MENUITEMINFOA
);
3829 mii
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
;
3831 mii
.fState
= MFS_ENABLED
;
3833 if(uFlags
& MF_BITMAP
)
3835 mii
.fType
|= MFT_BITMAP
;
3837 else if(uFlags
& MF_OWNERDRAW
)
3839 mii
.fType
|= MFT_OWNERDRAW
;
3842 if(uFlags
& MF_RIGHTJUSTIFY
)
3844 mii
.fType
|= MFT_RIGHTJUSTIFY
;
3846 if(uFlags
& MF_MENUBREAK
)
3848 mii
.fType
|= MFT_MENUBREAK
;
3850 if(uFlags
& MF_MENUBARBREAK
)
3852 mii
.fType
|= MFT_MENUBARBREAK
;
3854 if(uFlags
& MF_DISABLED
)
3856 mii
.fState
|= MFS_DISABLED
;
3858 if(uFlags
& MF_GRAYED
)
3860 mii
.fState
|= MFS_GRAYED
;
3863 mii
.dwTypeData
= (LPSTR
)lpNewItem
;
3864 if(uFlags
& MF_POPUP
)
3866 mii
.fMask
|= MIIM_SUBMENU
;
3867 mii
.hSubMenu
= (HMENU
)uIDNewItem
;
3871 mii
.fMask
|= MIIM_ID
;
3872 mii
.wID
= (UINT
)uIDNewItem
;
3874 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)!(MF_BYPOSITION
& uFlags
), &mii
);
3887 LPCMENUITEMINFOA lpmii
)
3890 UNICODE_STRING MenuText
;
3892 BOOL CleanHeap
= FALSE
;
3895 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
3896 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
3898 RtlMoveMemory ( &mi
, lpmii
, lpmii
->cbSize
);
3900 /* copy the text string */
3901 if((mi
.fMask
& (MIIM_TYPE
| MIIM_STRING
)) &&
3902 (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
) && mi
.dwTypeData
)
3904 Status
= HEAP_strdupAtoW ( &mi
.dwTypeData
, (LPCSTR
)mi
.dwTypeData
, &mi
.cch
);
3905 if (!NT_SUCCESS (Status
))
3907 SetLastError (RtlNtStatusToDosError(Status
));
3910 RtlInitUnicodeString(&MenuText
, (PWSTR
)mi
.dwTypeData
);
3911 mi
.dwTypeData
= (LPWSTR
)&MenuText
;
3915 res
= NtUserInsertMenuItem(hMenu
, uItem
, fByPosition
, &mi
);
3917 if ( CleanHeap
) HEAP_free ( mi
.dwTypeData
);
3932 LPCMENUITEMINFOW lpmii
)
3935 UNICODE_STRING MenuText
;
3937 BOOL CleanHeap
= FALSE
;
3938 HANDLE hHeap
= RtlGetProcessHeap();
3939 mi
.hbmpItem
= (HBITMAP
)0;
3941 // while we could just pass 'lpmii' to win32k, we make a copy so that
3942 // if a bad user passes bad data, we crash his process instead of the
3945 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
3946 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
3948 memcpy(&mi
, lpmii
, lpmii
->cbSize
);
3950 /* copy the text string */
3951 if((mi
.fMask
& (MIIM_TYPE
| MIIM_STRING
)) &&
3952 (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
) && mi
.dwTypeData
)
3956 if(!RtlCreateUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
))
3958 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY
));
3961 mi
.dwTypeData
= (LPWSTR
)&MenuText
;
3962 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
3967 res
= NtUserInsertMenuItem(hMenu
, uItem
, fByPosition
, &mi
);
3969 if(CleanHeap
) RtlFreeHeap (hHeap
, 0, mi
.dwTypeData
);
3984 UINT_PTR uIDNewItem
,
3988 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3989 mii
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
;
3991 mii
.fState
= MFS_ENABLED
;
3993 if(uFlags
& MF_BITMAP
)
3995 mii
.fType
|= MFT_BITMAP
;
3997 else if(uFlags
& MF_OWNERDRAW
)
3999 mii
.fType
|= MFT_OWNERDRAW
;
4002 if(uFlags
& MF_RIGHTJUSTIFY
)
4004 mii
.fType
|= MFT_RIGHTJUSTIFY
;
4006 if(uFlags
& MF_MENUBREAK
)
4008 mii
.fType
|= MFT_MENUBREAK
;
4010 if(uFlags
& MF_MENUBARBREAK
)
4012 mii
.fType
|= MFT_MENUBARBREAK
;
4014 if(uFlags
& MF_DISABLED
)
4016 mii
.fState
|= MFS_DISABLED
;
4018 if(uFlags
& MF_GRAYED
)
4020 mii
.fState
|= MFS_GRAYED
;
4023 mii
.dwTypeData
= (LPWSTR
)lpNewItem
;
4024 mii
.cch
= (NULL
== lpNewItem
? 0 : wcslen(lpNewItem
));
4025 if(uFlags
& MF_POPUP
)
4027 mii
.fType
|= MF_POPUP
;
4028 mii
.fMask
|= MIIM_SUBMENU
;
4029 mii
.hSubMenu
= (HMENU
)uIDNewItem
;
4033 mii
.fMask
|= MIIM_ID
;
4034 mii
.wID
= (UINT
)uIDNewItem
;
4036 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)!(MF_BYPOSITION
& uFlags
), &mii
);
4048 ROSMENUINFO MenuInfo
;
4050 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4058 LoadMenuA(HINSTANCE hInstance
,
4061 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4062 if (Resource
== NULL
)
4066 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4074 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4076 return(LoadMenuIndirectW(lpMenuTemplate
));
4084 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4087 WORD version
, offset
;
4088 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4090 version
= GET_WORD(p
);
4095 case 0: /* standard format is version of 0 */
4096 offset
= GET_WORD(p
);
4097 p
+= sizeof(WORD
) + offset
;
4098 if (!(hMenu
= CreateMenu())) return 0;
4099 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4105 case 1: /* extended format is version of 1 */
4106 offset
= GET_WORD(p
);
4107 p
+= sizeof(WORD
) + offset
;
4108 if (!(hMenu
= CreateMenu())) return 0;
4109 if (!MENUEX_ParseResource(p
, hMenu
))
4111 DestroyMenu( hMenu
);
4116 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4126 LoadMenuW(HINSTANCE hInstance
,
4129 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4130 if (Resource
== NULL
)
4134 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4148 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4161 UINT_PTR uIDNewItem
,
4178 UINT_PTR uIDNewItem
,
4196 return NtUserRemoveMenu(hMenu
, uPosition
, uFlags
);
4207 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4221 return NtUserSetMenuDefaultItem(hMenu
, uItem
, fByPos
);
4236 if(lpcmi
->cbSize
!= sizeof(MENUINFO
))
4239 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4240 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4253 HBITMAP hBitmapUnchecked
,
4254 HBITMAP hBitmapChecked
)
4270 LPMENUITEMINFOA lpmii
)
4286 LPMENUITEMINFOW lpmii
)
4303 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4308 SetLastError(ERROR_INVALID_MENU_HANDLE
);
4311 return NtUserSetSystemMenu(hwnd
, hMenu
);
4327 CONST RECT
*prcRect
)
4333 tpm
.cbSize
= sizeof(TPMPARAMS
);
4334 tpm
.rcExclude
= *prcRect
;
4337 return (BOOL
)NtUserTrackPopupMenuEx(hMenu
, uFlags
, x
, y
, hWnd
,
4338 (prcRect
? &tpm
: NULL
));
4355 return (BOOL
)NtUserTrackPopupMenuEx(hmenu
, fuFlags
, x
, y
, hwnd
, lptpm
);
4364 SetMenuContextHelpId(HMENU hmenu
,
4365 DWORD dwContextHelpId
)
4367 return NtUserSetMenuContextHelpId(hmenu
, dwContextHelpId
);
4376 GetMenuContextHelpId(HMENU hmenu
)
4379 mi
.cbSize
= sizeof(ROSMENUINFO
);
4380 mi
.fMask
= MIM_HELPID
;
4382 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
4384 return mi
.dwContextHelpID
;
4446 LPCWSTR lpszNewItem
,