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.51 2004/02/23 20:10:01 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
;
244 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
))
246 /* We have a string... */
247 if (Text
.MaximumLength
< (ItemInfo
->cch
+ 1) * sizeof(WCHAR
))
249 /* ...but we didn't allocate enough memory. Let's try again */
250 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
251 Text
.Buffer
= HeapAlloc(GetProcessHeap(), 0, (ItemInfo
->cch
+ 1) * sizeof(WCHAR
));
252 if (NULL
== Text
.Buffer
)
254 ItemInfo
->dwTypeData
= NULL
;
258 Text
.Length
= (ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
259 Text
.MaximumLength
= (ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
261 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
263 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
264 ItemInfo
->dwTypeData
= NULL
;
271 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
))
273 ItemInfo
->dwTypeData
= Text
.Buffer
;
274 ItemInfo
->cch
= Text
.Length
/ sizeof(WCHAR
);
275 Text
.Buffer
[ItemInfo
->cch
] = L
'\0';
279 /* Not a string, clean up the buffer */
280 if (NULL
!= Text
.Buffer
)
282 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
289 /***********************************************************************
290 * MenuSetRosMenuItemInfo
292 * Set full information about a menu item
295 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
301 StringVal
= (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
);
304 Text
.Buffer
= ItemInfo
->dwTypeData
;
305 Text
.Length
= wcslen(Text
.Buffer
) * sizeof(WCHAR
);
306 Text
.MaximumLength
= Text
.Length
+ sizeof(WCHAR
);
307 ItemInfo
->dwTypeData
= (LPWSTR
) &Text
;
309 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
310 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
312 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
316 ItemInfo
->dwTypeData
= Text
.Buffer
;
322 /***********************************************************************
323 * MenuCleanupRosMenuItemInfo
325 * Cleanup after use of MenuGet/SetRosMenuItemInfo
328 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
330 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
332 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
333 ItemInfo
->dwTypeData
= NULL
;
338 /***********************************************************************
339 * MenuGetAllRosMenuItemInfo
341 * Get full information about all menu items
344 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
348 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
353 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
354 if (NULL
== *ItemInfo
)
359 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
362 /***********************************************************************
363 * MenuCleanupAllRosMenuItemInfo
365 * Cleanup after use of MenuGetAllRosMenuItemInfo
368 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
370 HeapFree(GetProcessHeap(), 0, ItemInfo
);
373 /***********************************************************************
376 * Draw a single menu item.
379 MenuDrawMenuItem(HWND Wnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC Dc
,
380 PROSMENUITEMINFO Item
, UINT Height
, BOOL MenuBar
, UINT Action
)
385 if (0 != (Item
->fType
& MF_SYSMENU
))
388 if( !IsIconic(hwnd
) ) {
389 if (TWEAK_WineLook
> WIN31_LOOK
)
390 NC_DrawSysButton95( hwnd
, hdc
,
392 (MF_HILITE
| MF_MOUSESELECT
) );
394 NC_DrawSysButton( hwnd
, hdc
,
396 (MF_HILITE
| MF_MOUSESELECT
) );
403 if (0 != (Item
->fType
& MF_OWNERDRAW
))
406 ** Experimentation under Windows reveals that an owner-drawn
407 ** menu is given the rectangle which includes the space it requested
408 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
409 ** and a popup-menu arrow. This is the value of lpitem->rect.
410 ** Windows will leave all drawing to the application except for
411 ** the popup-menu arrow. Windows always draws that itself, after
412 ** the menu owner has finished drawing.
416 dis
.CtlType
= ODT_MENU
;
418 dis
.itemID
= Item
->wID
;
419 dis
.itemData
= (DWORD
)Item
->dwItemData
;
421 if (0 != (Item
->fState
& MF_CHECKED
))
423 dis
.itemState
|= ODS_CHECKED
;
425 if (0 != (Item
->fState
& MF_GRAYED
))
427 dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
429 if (0 != (Item
->fState
& MF_HILITE
))
431 dis
.itemState
|= ODS_SELECTED
;
433 dis
.itemAction
= Action
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
434 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
436 dis
.rcItem
= Item
->Rect
;
437 DPRINT("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
438 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner
,
439 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
440 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
442 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
443 /* Fall through to draw popup-menu arrow */
446 DPRINT("rect={%ld,%ld,%ld,%ld}\n", Item
->rect
.left
, Item
->rect
.top
,
447 Item
->rect
.right
, Item
->rect
.bottom
);
449 if (MenuBar
&& 0 != (Item
->fType
& MF_SEPARATOR
))
456 if (0 == (Item
->fType
& MF_OWNERDRAW
))
458 if (Item
->fState
& MF_HILITE
)
462 DrawEdge(Dc
, &Rect
, BDR_SUNKENOUTER
, BF_RECT
);
466 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
471 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_MENU
));
475 SetBkMode(Dc
, TRANSPARENT
);
477 if (0 == (Item
->fType
& MF_OWNERDRAW
))
479 /* vertical separator */
480 if (! MenuBar
&& 0 != (Item
->fType
& MF_MENUBARBREAK
))
484 rc
.bottom
= Height
- 3;
485 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
488 /* horizontal separator */
489 if (0 != (Item
->fType
& MF_SEPARATOR
))
494 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
495 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_TOP
);
503 if (0 != (Item
->fState
& MF_HILITE
))
507 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
508 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
512 if (0 != (Item
->fState
& MF_GRAYED
))
514 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
518 SetTextColor(Dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
520 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
525 if (0 != (Item
->fState
& MF_GRAYED
))
527 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
531 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
533 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
537 /* helper lines for debugging */
538 FrameRect(Dc
, &Rect
, GetStockObject(BLACK_BRUSH
));
539 SelectObject(Dc
, SYSCOLOR_GetPen(COLOR_WINDOWFRAME
));
540 MoveToEx(Dc
, Rect
.left
, (Rect
.top
+ Rect
.bottom
) / 2, NULL
);
541 LineTo(Dc
, Rect
.right
, (Rect
.top
+ Rect
.bottom
) / 2);
546 INT y
= Rect
.top
+ Rect
.bottom
;
547 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
548 UINT CheckBitmapHeight
= GetSystemMetrics(SM_CYMENUCHECK
);
550 if (0 == (Item
->fType
& MF_OWNERDRAW
))
552 /* Draw the check mark
555 * Custom checkmark bitmaps are monochrome but not always 1bpp.
558 HBITMAP bm
= 0 != (Item
->fState
& MF_CHECKED
) ? Item
->hCheckBit
: Item
->hUnCheckBit
;
559 if (NULL
!= bm
) /* we have a custom bitmap */
561 HDC DcMem
= CreateCompatibleDC(Dc
);
562 SelectObject(DcMem
, bm
);
563 BitBlt(Dc
, Rect
.left
, (y
- CheckBitmapHeight
) / 2,
564 CheckBitmapWidth
, CheckBitmapHeight
,
565 DcMem
, 0, 0, SRCCOPY
);
568 else if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
570 if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
574 HBITMAP bm
= CreateBitmap(CheckBitmapWidth
, CheckBitmapHeight
, 1, 1, NULL
);
575 HDC DcMem
= CreateCompatibleDC(Dc
);
576 SelectObject(DcMem
, bm
);
577 SetRect( &r
, 0, 0, CheckBitmapWidth
, CheckBitmapHeight
);
578 DrawFrameControl(DcMem
, &r
, DFC_MENU
,
579 0 != (Item
->fType
& MFT_RADIOCHECK
) ?
580 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
581 BitBlt(Dc
, Rect
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
582 DcMem
, 0, 0, SRCCOPY
);
589 /* Draw the popup-menu arrow */
590 if (lpitem
->fType
& MF_POPUP
)
592 HDC hdcMem
= CreateCompatibleDC( hdc
);
595 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
596 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
597 (y
- arrow_bitmap_height
) / 2,
598 arrow_bitmap_width
, arrow_bitmap_height
,
599 hdcMem
, 0, 0, SRCCOPY
);
600 SelectObject( hdcMem
, hOrigBitmap
);
605 Rect
.left
+= CheckBitmapWidth
;
606 Rect
.right
-= ArrowBitmapWidth
;
609 /* Done for owner-drawn */
610 if (0 != (Item
->fType
& MF_OWNERDRAW
))
615 /* Draw the item text or bitmap */
616 if (IS_BITMAP_ITEM(Item
->fType
))
619 MENU_DrawBitmapItem( hdc
, lpitem
, &rect
, menuBar
);
623 /* No bitmap - process text if present */
624 else if (IS_STRING_ITEM(Item
->fType
))
627 HFONT FontOld
= NULL
;
629 UINT uFormat
= MenuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
630 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
632 if (0 != (Item
->fState
& MFS_DEFAULT
))
634 FontOld
= SelectObject(Dc
, hMenuFontBold
);
639 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
640 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
643 Text
= (PWCHAR
) Item
->dwTypeData
;
644 for (i
= 0; L
'\0' != Text
[i
]; i
++)
646 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
652 if (0 != (Item
->fState
& MF_GRAYED
))
654 if (0 == (Item
->fState
& MF_HILITE
))
656 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
657 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
658 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
659 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
661 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
664 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
666 /* paint the shortcut text */
667 if (! MenuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
669 if (L
'\t' == Text
[i
])
671 Rect
.left
= Item
->XTab
;
672 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
676 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
679 if (0 != (Item
->fState
& MF_GRAYED
))
681 if (0 == (Item
->fState
& MF_HILITE
))
683 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
684 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
685 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
686 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
688 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
690 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
695 SelectObject(Dc
, FontOld
);
700 /***********************************************************************
703 * Paint a popup menu.
706 MenuDrawPopupMenu(HWND Wnd
, HDC Dc
, HMENU Menu
)
708 HBRUSH PrevBrush
= NULL
;
711 ROSMENUINFO MenuInfo
;
712 ROSMENUITEMINFO ItemInfo
;
715 DPRINT("wnd=%x dc=%x menu=%x\n", Wnd
, Dc
, Menu
);
717 GetClientRect(Wnd
, &Rect
);
719 if (NULL
!= (PrevBrush
= SelectObject(Dc
, GetSysColorBrush(COLOR_MENU
)))
720 && NULL
!= SelectObject(Dc
, hMenuFont
))
722 Rectangle(Dc
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
724 PrevPen
= SelectObject(Dc
, GetStockObject(NULL_PEN
));
727 DrawEdge(Dc
, &Rect
, EDGE_RAISED
, BF_RECT
);
729 /* draw menu items */
731 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 != MenuInfo
.MenuItemCount
)
733 MenuInitRosMenuItemInfo(&ItemInfo
);
735 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
737 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
739 MenuDrawMenuItem(Wnd
, &MenuInfo
, MenuInfo
.WndOwner
, Dc
, &ItemInfo
,
740 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
747 SelectObject(Dc
, PrevBrush
);
752 static LRESULT WINAPI
753 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
755 DPRINT("hwnd=%x msg=0x%04x wp=0x%04x lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
761 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
762 SetWindowLongW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
766 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
767 return MA_NOACTIVATE
;
772 BeginPaint(Wnd
, &ps
);
773 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongW(Wnd
, 0));
782 /* zero out global pointer in case resident popup window was destroyed. */
792 if (0 == GetWindowLongW(Wnd
, 0))
794 OutputDebugStringA("no menu to display\n");
799 SetWindowLongW(Wnd
, 0, 0);
803 case MM_SETMENUHANDLE
:
804 SetWindowLongW(Wnd
, 0, wParam
);
807 case MM_GETMENUHANDLE
:
808 return GetWindowLongW(Wnd
, 0);
811 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
817 /**********************************************************************
818 * MENUEX_ParseResource
820 * Parse an extended menu resource and add items to the menu.
821 * Return a pointer to the end of the resource.
823 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
825 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
833 mii
.cbSize
= sizeof(mii
);
834 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
835 mii
.fType
= GET_DWORD(res
);
836 res
+= sizeof(DWORD
);
837 mii
.fState
= GET_DWORD(res
);
838 res
+= sizeof(DWORD
);
839 mii
.wID
= GET_DWORD(res
);
840 res
+= sizeof(DWORD
);
841 resinfo
= GET_WORD(res
);
843 /* Align the text on a word boundary. */
844 res
+= (~((int)res
- 1)) & 1;
845 mii
.dwTypeData
= (LPWSTR
) res
;
846 res
+= (1 + wcslen(mii
.dwTypeData
)) * sizeof(WCHAR
);
847 /* Align the following fields on a dword boundary. */
848 res
+= (~((int)res
- 1)) & 3;
850 if (resinfo
& 1) /* Pop-up? */
852 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
853 res
+= sizeof(DWORD
);
854 mii
.hSubMenu
= CreatePopupMenu();
857 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
859 DestroyMenu(mii
.hSubMenu
);
862 mii
.fMask
|= MIIM_SUBMENU
;
863 mii
.fType
|= MF_POPUP
;
865 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
867 DbgPrint("WARN: Converting NULL menu item %04x, type %04x to SEPARATOR\n",
869 mii
.fType
|= MF_SEPARATOR
;
871 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
873 while (!(resinfo
& MF_END
));
878 /**********************************************************************
881 * Parse a standard menu resource and add items to the menu.
882 * Return a pointer to the end of the resource.
884 * NOTE: flags is equivalent to the mtOption field
886 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
895 flags
= GET_WORD(res
);
897 /* remove MF_END flag before passing it to AppendMenu()! */
898 end
= (flags
& MF_END
);
899 if(end
) flags
^= MF_END
;
902 if(!(flags
& MF_POPUP
))
909 res
+= strlen(str
) + 1;
911 res
+= (wcslen((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
912 if (flags
& MF_POPUP
)
914 hSubMenu
= CreatePopupMenu();
915 if(!hSubMenu
) return NULL
;
916 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
919 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
921 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
923 else /* Not a popup */
926 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
928 AppendMenuW(hMenu
, flags
, id
,
929 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
938 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
942 hUser32
= GetModuleHandleW(L
"USER32");
943 Result
= (LRESULT
)LoadMenuW(hUser32
, L
"SYSMENU");
944 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
951 NONCLIENTMETRICSW ncm
;
953 /* get the menu font */
954 if(!hMenuFont
|| !hMenuFontBold
)
956 ncm
.cbSize
= sizeof(ncm
);
957 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
959 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
963 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
964 if(hMenuFont
== NULL
)
966 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
970 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
971 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
972 if(hMenuFontBold
== NULL
)
974 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
984 MeasureMenuItem(HWND hWnd
, HMENU mnu
, HDC hDC
, PROSMENUITEMINFO mii
, LPWSTR str
)
987 MEASUREITEMSTRUCT mis
;
990 if(mii
->fType
& MFT_OWNERDRAW
)
992 /* send WM_MEASUREITEM message to window */
993 mis
.CtlType
= ODT_MENU
;
995 mis
.itemID
= mii
->wID
;
998 mis
.itemData
= mii
->dwItemData
;
999 res
= (BOOL
)SendMessageW(hWnd
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1002 mii
->Rect
.right
= mii
->Rect
.left
+ mis
.itemWidth
;
1003 mii
->Rect
.bottom
= mii
->Rect
.top
+ mis
.itemHeight
;
1007 /* FIXME calculate size internally assuming the menu item is empty */
1008 mii
->Rect
.right
= mii
->Rect
.left
+ 1;
1009 mii
->Rect
.bottom
= mii
->Rect
.top
+ 1;
1015 GetTextExtentPoint32W(hDC
, str
, mii
->cch
, &sz
);
1016 /* FIXME calculate the size of the menu item */
1017 mii
->Rect
.right
= mii
->Rect
.left
+ sz
.cx
+ 6;
1018 mii
->Rect
.bottom
= mii
->Rect
.top
+ max(sz
.cy
, GetSystemMetrics(SM_CYMENU
));
1024 DrawMenuItem(HWND hWnd
, HMENU mnu
, HDC hDC
, PROSMENUITEMINFO mii
, LPWSTR str
)
1029 if(mii
->fType
& MFT_OWNERDRAW
)
1031 /* send WM_DRAWITEM message to window */
1032 dis
.CtlType
= ODT_MENU
;
1034 dis
.itemID
= mii
->wID
;
1035 dis
.itemAction
= ODA_DRAWENTIRE
; /* FIXME */
1036 dis
.itemState
= 0; /* FIXME */
1037 dis
.hwndItem
= (HWND
)mnu
;
1039 RtlCopyMemory(&dis
.rcItem
, &mii
->Rect
, sizeof(RECT
));
1040 dis
.itemData
= mii
->dwItemData
;
1041 res
= (BOOL
)SendMessageW(hWnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1046 /* FIXME draw the menu item */
1047 SetTextColor(hDC
, COLOR_MENUTEXT
);
1048 SetBkMode(hDC
, TRANSPARENT
);
1049 DrawTextW(hDC
, str
, mii
->cch
, &mii
->Rect
, DT_SINGLELINE
| DT_VCENTER
| DT_CENTER
);
1055 /***********************************************************************
1058 * Calculate the size of the menu item and store it in ItemInfo->rect.
1060 static void FASTCALL
1061 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, HWND WndOwner
,
1062 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1065 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1067 DPRINT("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1069 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1071 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1074 ** Experimentation under Windows reveals that an owner-drawn
1075 ** menu is expected to return the size of the content part of
1076 ** the menu item, not including the checkmark nor the submenu
1077 ** arrow. Windows adds those values itself and returns the
1078 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1080 MEASUREITEMSTRUCT mis
;
1081 mis
.CtlType
= ODT_MENU
;
1083 mis
.itemID
= ItemInfo
->wID
;
1084 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1087 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1088 ItemInfo
->Rect
.right
+= mis
.itemWidth
;
1092 ItemInfo
->Rect
.right
+= MENU_BAR_ITEMS_SPACE
;
1094 /* under at least win95 you seem to be given a standard
1095 height for the menu and the height value is ignored */
1097 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENU
) - 1;
1101 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1104 DPRINT("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1105 /* Fall through to get check/arrow width calculation. */
1108 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1110 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1116 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1117 if (0 != (ItemInfo
->fType
& MF_POPUP
))
1119 ItemInfo
->Rect
.right
+= ArrowBitmapWidth
;
1123 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1128 if (IS_BITMAP_ITEM(ItemInfo
->fType
))
1133 MENU_GetBitmapItemSize( (int)lpitem
->text
, lpitem
->dwItemData
, &size
);
1134 lpitem
->rect
.right
+= size
.cx
;
1135 lpitem
->rect
.bottom
+= size
.cy
;
1137 /* Leave space for the sunken border */
1138 lpitem
->rect
.right
+= 2;
1139 lpitem
->rect
.bottom
+= 2;
1143 /* it must be a text item - unless it's the system menu */
1144 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && IS_STRING_ITEM(ItemInfo
->fType
))
1148 GetTextExtentPoint32W(Dc
, (LPWSTR
) ItemInfo
->dwTypeData
,
1149 wcslen((LPWSTR
) ItemInfo
->dwTypeData
), &Size
);
1151 ItemInfo
->Rect
.right
+= Size
.cx
;
1152 ItemInfo
->Rect
.bottom
+= max(Size
.cy
, GetSystemMetrics(SM_CYMENU
) - 1);
1157 ItemInfo
->Rect
.right
+= MENU_BAR_ITEMS_SPACE
;
1159 else if ((p
= wcschr((LPWSTR
) ItemInfo
->dwTypeData
, L
'\t' )) != NULL
)
1161 /* Item contains a tab (only meaningful in popup menus) */
1162 GetTextExtentPoint32W(Dc
, (LPWSTR
) ItemInfo
->dwTypeData
,
1163 (int)(p
- (LPWSTR
) ItemInfo
->dwTypeData
), &Size
);
1164 ItemInfo
->XTab
= CheckBitmapWidth
+ MENU_TAB_SPACE
+ Size
.cx
;
1165 ItemInfo
->Rect
.right
+= MENU_TAB_SPACE
;
1169 if (NULL
!= wcschr((LPWSTR
) ItemInfo
->dwTypeData
, L
'\b'))
1171 ItemInfo
->Rect
.right
+= MENU_TAB_SPACE
;
1173 ItemInfo
->XTab
= ItemInfo
->Rect
.right
- CheckBitmapWidth
1178 DPRINT("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1181 /***********************************************************************
1182 * MenuPopupMenuCalcSize
1184 * Calculate the size of a popup menu.
1186 static void FASTCALL
1187 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1189 ROSMENUITEMINFO ItemInfo
;
1192 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1194 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1195 if (0 == MenuInfo
->MenuItemCount
)
1197 MenuSetRosMenuInfo(MenuInfo
);
1202 SelectObject(Dc
, hMenuFont
);
1207 MenuInitRosMenuItemInfo(&ItemInfo
);
1208 while (Start
< MenuInfo
->MenuItemCount
)
1213 MaxTab
= MaxTabWidth
= 0;
1215 /* Parse items until column break or end of menu */
1216 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1218 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1220 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1221 MenuSetRosMenuInfo(MenuInfo
);
1225 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1230 MenuCalcItemSize(Dc
, &ItemInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1231 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1233 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1234 MenuSetRosMenuInfo(MenuInfo
);
1238 if (0 != (ItemInfo
.fType
& MF_MENUBARBREAK
))
1242 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1243 OrgY
= ItemInfo
.Rect
.bottom
;
1244 if (IS_STRING_ITEM(ItemInfo
.fType
) && 0 != ItemInfo
.XTab
)
1246 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1247 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1251 /* Finish the column (set all items to the largest width found) */
1252 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1255 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1257 ItemInfo
.Rect
.right
= MaxX
;
1258 if (IS_STRING_ITEM(ItemInfo
.fType
) && 0 != ItemInfo
.XTab
)
1260 ItemInfo
.XTab
= MaxTab
;
1262 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1266 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1269 MenuInfo
->Width
= MaxX
;
1271 /* space for 3d border */
1272 MenuInfo
->Height
+= 2;
1273 MenuInfo
->Width
+= 2;
1275 ReleaseDC(NULL
, Dc
);
1276 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1277 MenuSetRosMenuInfo(MenuInfo
);
1280 #if 0 /* Not used yet */
1281 /***********************************************************************
1282 * MenuMenuBarCalcSize
1284 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1285 * height is off by 1 pixel which causes lengthy window relocations when
1286 * active document window is maximized/restored.
1288 * Calculate the size of the menu bar.
1290 static void FASTCALL
1291 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1293 ROSMENUITEMINFO ItemInfo
;
1294 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1296 if (NULL
== Rect
|| NULL
== MenuInfo
)
1300 if (0 == MenuInfo
->MenuItemCount
)
1305 DPRINT("left=%ld top=%ld right=%ld bottom=%ld\n",
1306 Rrect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1307 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1308 MenuInfo
->Height
= 0;
1309 MaxY
= Rect
->top
+ 1;
1312 MenuInitRosMenuItemInfo(&ItemInfo
);
1313 while (Start
< MenuInfo
->MenuItemCount
)
1315 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1317 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1323 /* Parse items until line break or end of menu */
1324 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1326 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1331 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1336 DPRINT("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1337 MenuCalcItemSize(Dc
, &ItemInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1338 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1340 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1344 if (ItemInfo
.Rect
.right
> Rect
->right
)
1352 ItemInfo
.Rect
.right
= Rect
->right
;
1355 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1356 OrgX
= ItemInfo
.Rect
.right
;
1357 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1359 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1361 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1367 /* Finish the line (set all items to the largest height found) */
1370 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1372 ItemInfo
.Rect
.bottom
= MaxY
;
1373 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1379 Rect
->bottom
= MaxY
;
1380 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1381 MenuSetRosMenuInfo(MenuInfo
);
1385 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1386 /* the last item (if several lines, only move the last line) */
1387 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1389 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1392 OrgY
= ItemInfo
.Rect
.top
;
1394 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1400 if (ItemInfo
.Rect
.top
!= OrgY
)
1402 break; /* Other line */
1404 if (OrgX
<= ItemInfo
.Rect
.right
)
1406 break; /* Too far right already */
1408 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1409 ItemInfo
.Rect
.right
= OrgX
;
1410 OrgX
= ItemInfo
.Rect
.left
;
1411 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1412 if (HelpPos
+ 1 <= i
&&
1413 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1415 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1421 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1427 MenuDrawMenuBar(HDC hDC
, LPRECT Rect
, HWND hWnd
, BOOL Draw
)
1433 DWORD BufSize
, Items
, Items2
, hItems
;
1434 ROSMENUITEMINFO
*mii
;
1436 SETMENUITEMRECT smir
;
1440 mnu
= GetMenu(hWnd
); /* Fixme - pass menu handle as parameter */
1441 /* get menu item list size */
1442 BufSize
= NtUserBuildMenuItemList(mnu
, (VOID
*)1, 0, 0);
1445 hHeap
= GetProcessHeap();
1446 hBuf
= HeapAlloc(hHeap
, 0, BufSize
);
1450 /* copy menu items into buffer */
1451 Items
= Items2
= NtUserBuildMenuItemList(mnu
, Buf
, BufSize
, 0);
1455 bottom
= line
= Rect
->top
;
1456 smir
.fByPosition
= TRUE
;
1458 /* calculate menu item rectangles */
1463 mii
= (PROSMENUITEMINFO
)Buf
;
1464 Buf
+= sizeof(ROSMENUITEMINFO
);
1467 str
= (LPWSTR
)mii
->dwTypeData
;
1473 mii
->Rect
.left
= omir
.right
+ 1;
1474 mii
->Rect
.top
= omir
.top
;
1475 mii
->Rect
.right
+= mii
->Rect
.left
;
1476 mii
->Rect
.bottom
+= mii
->Rect
.top
;
1480 mii
->Rect
.left
= Rect
->left
;
1481 mii
->Rect
.top
= Rect
->top
;
1483 if((mii
->fType
& MFT_RIGHTJUSTIFY
) && !milist
)
1485 milist
= mih
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, Items
* sizeof(PROSMENUITEMINFO
));
1489 MeasureMenuItem(hWnd
, mnu
, hDC
, mii
, str
);
1491 if((mii
->Rect
.right
> Rect
->right
) || (mii
->fType
& (MFT_MENUBREAK
| MFT_MENUBARBREAK
)))
1493 mii
->Rect
.right
-= (mii
->Rect
.left
- Rect
->left
);
1494 mii
->Rect
.left
= Rect
->left
;
1495 mii
->Rect
.top
+= line
;
1496 mii
->Rect
.bottom
+= line
;
1497 line
= mii
->Rect
.bottom
- mii
->Rect
.top
;
1502 smir
.rcRect
= mii
->Rect
;
1503 NtUserSetMenuItemRect(mnu
, &smir
);
1511 bottom
= max(bottom
, mii
->Rect
.bottom
);
1512 line
= max(line
, mii
->Rect
.bottom
- mii
->Rect
.top
);
1516 /* align help menus to the right */
1522 smir
.uItem
= Items2
- 1;
1526 PROSMENUITEMINFO omii
;
1529 mii
= (PROSMENUITEMINFO
)(*(--mih
));
1531 if(omii
&& ((mii
->Rect
.right
> x
) || (omii
->fType
& (MFT_MENUBREAK
| MFT_MENUBARBREAK
))))
1536 wd
= (mii
->Rect
.right
- mii
->Rect
.left
);
1537 mii
->Rect
.right
= x
- 1;
1538 mii
->Rect
.left
= mii
->Rect
.right
- wd
;
1541 smir
.rcRect
= mii
->Rect
;
1543 NtUserSetMenuItemRect(mnu
, &smir
);
1550 HeapFree(GetProcessHeap(), 0, milist
);
1552 bottom
= max(bottom
, Rect
->top
+ GetSystemMetrics(SM_CYMENU
));
1553 if(bottom
- Rect
->top
> 0)
1555 NtUserSetMenuBarHeight(mnu
, bottom
- Rect
->top
);
1560 bottom
= Rect
->bottom
;
1561 FillRect(hDC
, Rect
, GetSysColorBrush(COLOR_MENU
));
1563 /* draw menu items */
1566 mii
= (PROSMENUITEMINFO
)Buf
;
1567 Buf
+= sizeof(ROSMENUITEMINFO
);
1570 str
= (LPWSTR
)mii
->dwTypeData
;
1574 /* DbgPrint("Draw menu item %ws at (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
1575 DrawMenuItem(hWnd
, mnu
, hDC
, mii
, str
);
1580 HeapFree(hHeap
, 0, hBuf
);
1583 return max(bottom
- Rect
->top
, GetSystemMetrics(SM_CYMENU
));
1586 /***********************************************************************
1589 static BOOL FASTCALL
1590 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1592 DPRINT("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1596 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1597 if (0 == (Flags
& TPM_NONOTIFY
))
1599 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1602 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1604 if (0 == (Flags
& TPM_NONOTIFY
))
1606 ROSMENUINFO MenuInfo
;
1608 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1610 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 == MenuInfo
.Height
)
1612 /* app changed/recreated menu bar entries in WM_INITMENU
1613 Recalculate menu sizes else clicks will not work */
1614 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1615 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1624 /***********************************************************************
1627 * Display a popup menu.
1629 static BOOL FASTCALL
1630 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1631 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1633 ROSMENUINFO MenuInfo
;
1634 ROSMENUITEMINFO ItemInfo
;
1637 DPRINT("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1638 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1640 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1645 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1647 MenuInitRosMenuItemInfo(&ItemInfo
);
1648 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1650 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1651 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1653 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1654 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1657 /* store the owner for DrawItem */
1658 MenuInfo
.WndOwner
= WndOwner
;
1659 MenuSetRosMenuInfo(&MenuInfo
);
1661 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1663 /* adjust popup menu pos so that it fits within the desktop */
1665 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1666 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1668 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1672 X
-= Width
- XAnchor
;
1674 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1676 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1684 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1688 Y
-= Height
+ YAnchor
;
1690 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1692 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
1701 /* NOTE: In Windows, top menu popup is not owned. */
1702 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
1703 WS_POPUP
, X
, Y
, Width
, Height
,
1704 WndOwner
, 0, (HINSTANCE
) GetWindowLongW(WndOwner
, GWL_HINSTANCE
),
1705 (LPVOID
) MenuInfo
.Self
);
1706 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
1710 if (NULL
== TopPopup
)
1712 TopPopup
= MenuInfo
.Wnd
;
1715 /* Display the window */
1716 SetWindowPos(MenuInfo
.Wnd
, HWND_TOP
, 0, 0, 0, 0,
1717 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1718 UpdateWindow(MenuInfo
.Wnd
);
1723 /***********************************************************************
1726 * Find a Sub menu. Return the position of the submenu, and modifies
1727 * *hmenu in case it is found in another sub-menu.
1728 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
1730 static UINT FASTCALL
1731 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
1733 ROSMENUINFO MenuInfo
;
1734 ROSMENUITEMINFO ItemInfo
;
1739 if ((HMENU
) 0xffff == *Menu
1740 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
1742 return NO_SELECTED_ITEM
;
1745 MenuInitRosMenuItemInfo(&ItemInfo
);
1746 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1748 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1750 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1751 return NO_SELECTED_ITEM
;
1753 if (0 == (ItemInfo
.fType
& MF_POPUP
))
1757 if (ItemInfo
.hSubMenu
== SubTarget
)
1759 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1762 SubMenu
= ItemInfo
.hSubMenu
;
1763 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
1764 if (NO_SELECTED_ITEM
!= Pos
)
1770 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1772 return NO_SELECTED_ITEM
;
1775 /***********************************************************************
1778 static void FASTCALL
1779 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
1780 BOOL SendMenuSelect
, HMENU TopMenu
)
1783 ROSMENUITEMINFO ItemInfo
;
1784 ROSMENUINFO TopMenuInfo
;
1787 DPRINT("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
1789 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
1794 if (MenuInfo
->FocusedItem
== Index
)
1799 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
1801 Dc
= GetDC(MenuInfo
->Wnd
);
1805 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1808 if (NULL
== TopPopup
)
1810 TopPopup
= MenuInfo
->Wnd
;
1813 SelectObject(Dc
, hMenuFont
);
1814 MenuInitRosMenuItemInfo(&ItemInfo
);
1816 /* Clear previous highlighted item */
1817 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1819 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1821 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1822 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1824 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
1825 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1829 /* Highlight new item (if any) */
1830 MenuInfo
->FocusedItem
= Index
;
1831 MenuSetRosMenuInfo(MenuInfo
);
1832 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1834 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1836 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1838 ItemInfo
.fState
|= MF_HILITE
;
1839 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1840 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
1841 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1846 SendMessageW(WndOwner
, WM_MENUSELECT
,
1847 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
1848 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1849 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
1853 else if (SendMenuSelect
)
1855 if (NULL
!= TopMenu
)
1857 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
1858 if (NO_SELECTED_ITEM
!= Pos
)
1860 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
1861 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
1863 SendMessageW(WndOwner
, WM_MENUSELECT
,
1864 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1866 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1873 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1874 ReleaseDC(MenuInfo
->Wnd
, Dc
);
1877 /***********************************************************************
1880 * Moves currently selected item according to the Offset parameter.
1881 * If there is no selection then it should select the last item if
1882 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1884 static void FASTCALL
1885 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1888 ROSMENUITEMINFO ItemInfo
;
1890 DPRINT("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, offset
);
1892 MenuInitRosMenuItemInfo(&ItemInfo
);
1893 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1895 if (1 == MenuInfo
->MenuItemCount
)
1897 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1902 for (i
= MenuInfo
->FocusedItem
+ Offset
;
1903 0 <= i
&& i
< MenuInfo
->MenuItemCount
;
1906 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1907 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1909 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1910 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1917 for (i
= (0 < Offset
) ? 0 : MenuInfo
->MenuItemCount
- 1;
1918 0 <= i
&& i
< MenuInfo
->MenuItemCount
; i
+= Offset
)
1920 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1921 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1923 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1924 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1929 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1932 /***********************************************************************
1933 * MenuInitSysMenuPopup
1935 * Grey the appropriate items in System menu.
1937 static void FASTCALL
1938 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
)
1942 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1943 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1944 Gray
= 0 != (Style
& WS_MAXIMIZE
);
1945 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1946 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
1947 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1948 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
1949 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1950 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1951 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1952 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
1954 /* The menu item must keep its state if it's disabled */
1957 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
1961 /***********************************************************************
1964 * Display the sub-menu of the selected item of this menu.
1965 * Return the handle of the submenu, or menu if no submenu to display.
1967 static HMENU FASTCALL
1968 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
1970 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
1972 ROSMENUITEMINFO ItemInfo
;
1973 ROSMENUINFO SubMenuInfo
;
1977 DPRINT("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
1979 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
1981 return MenuInfo
->Self
;
1984 MenuInitRosMenuItemInfo(&ItemInfo
);
1985 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1987 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1988 return MenuInfo
->Self
;
1990 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
1992 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1993 return MenuInfo
->Self
;
1996 /* message must be sent before using item,
1997 because nearly everything may be changed by the application ! */
1999 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2000 if (0 == (Flags
& TPM_NONOTIFY
))
2002 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2003 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2006 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2008 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2009 return MenuInfo
->Self
;
2011 Rect
= ItemInfo
.Rect
;
2013 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2014 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2016 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2018 Dc
= GetDC(MenuInfo
->Wnd
);
2022 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2025 SelectObject(Dc
, hMenuFont
);
2027 ItemInfo
.fState
|= MF_HILITE
;
2028 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2029 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2030 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2031 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2034 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2035 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2037 ItemInfo
.Rect
= Rect
;
2040 ItemInfo
.fState
|= MF_MOUSESELECT
;
2042 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2044 if (IS_SYSTEM_MENU(MenuInfo
))
2046 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
,
2047 GetWindowLongW(MenuInfo
->Wnd
, GWL_STYLE
),
2048 GetClassLongW(MenuInfo
->Wnd
, GCL_STYLE
));
2050 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2051 Rect
.top
= Rect
.bottom
;
2052 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2053 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2057 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2058 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2060 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2061 Rect
.top
+= ItemInfo
.Rect
.top
;
2062 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2063 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
;
2067 Rect
.left
+= ItemInfo
.Rect
.left
;
2068 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2069 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2070 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2074 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2075 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2076 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2078 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2081 Ret
= ItemInfo
.hSubMenu
;
2082 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2087 /***********************************************************************
2090 * Hide the sub-popup menus of this menu.
2092 static void FASTCALL
2093 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2095 ROSMENUINFO SubMenuInfo
;
2096 ROSMENUITEMINFO ItemInfo
;
2098 DPRINT("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2100 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2102 MenuInitRosMenuItemInfo(&ItemInfo
);
2103 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2104 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2105 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2107 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2110 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2111 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2112 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2114 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2115 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2116 DestroyWindow(SubMenuInfo
.Wnd
);
2117 SubMenuInfo
.Wnd
= NULL
;
2118 MenuSetRosMenuInfo(&SubMenuInfo
);
2123 /***********************************************************************
2124 * MenuSwitchTracking
2126 * Helper function for menu navigation routines.
2128 static void FASTCALL
2129 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2131 ROSMENUINFO TopMenuInfo
;
2133 DPRINT("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2135 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2136 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2137 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2139 /* both are top level menus (system and menu-bar) */
2140 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2141 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2142 Mt
->TopMenu
= PtMenuInfo
->Self
;
2146 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2149 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2152 /***********************************************************************
2153 * MenuExecFocusedItem
2155 * Execute a menu item (for instance when user pressed Enter).
2156 * Return the wID of the executed item. Otherwise, -1 indicating
2157 * that no menu item was executed;
2158 * Have to receive the flags for the TrackPopupMenu options to avoid
2159 * sending unwanted message.
2163 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2165 ROSMENUITEMINFO ItemInfo
;
2168 DPRINT("%p menu=%p\n", Mt
, MenuInfo
);
2170 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2175 MenuInitRosMenuItemInfo(&ItemInfo
);
2176 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2178 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2182 DPRINT("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2184 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2186 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2187 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2189 /* If TPM_RETURNCMD is set you return the id, but
2190 do not send a message to the owner */
2191 if (0 == (Flags
& TPM_RETURNCMD
))
2193 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2195 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2196 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2200 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2204 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2210 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2216 /***********************************************************************
2219 * Return TRUE if we can go on with menu tracking.
2221 static BOOL FASTCALL
2222 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2225 ROSMENUINFO MenuInfo
;
2226 ROSMENUITEMINFO Item
;
2228 DPRINT("%x PtMenu=%p\n", Mt
, PtMenu
);
2232 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2236 if (IS_SYSTEM_MENU(&MenuInfo
))
2242 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2244 MenuInitRosMenuItemInfo(&Item
);
2245 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2247 MenuCleanupRosMenuItemInfo(&Item
);
2251 if (MenuInfo
.FocusedItem
!= Index
)
2253 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2256 /* If the popup menu is not already "popped" */
2257 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2259 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2262 MenuCleanupRosMenuItemInfo(&Item
);
2267 /* else the click was on the menu bar, finish the tracking */
2272 /***********************************************************************
2275 * Return the value of MenuExecFocusedItem if
2276 * the selected item was not a popup. Else open the popup.
2277 * A -1 return value indicates that we go on with menu tracking.
2281 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2284 ROSMENUINFO MenuInfo
;
2285 ROSMENUITEMINFO ItemInfo
;
2287 DPRINT("%p hmenu=%x\n", Mt
, PtMenu
);
2292 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2297 if (! IS_SYSTEM_MENU(&MenuInfo
))
2299 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2301 MenuInitRosMenuItemInfo(&ItemInfo
);
2302 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2303 MenuInfo
.FocusedItem
== Id
)
2305 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2307 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2308 return MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2310 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2312 /* If we are dealing with the top-level menu */
2313 /* and this is a click on an already "popped" item: */
2314 /* Stop the menu tracking and close the opened submenus */
2315 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2317 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2321 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2322 MenuInfo
.TimeToHide
= TRUE
;
2323 MenuSetRosMenuInfo(&MenuInfo
);
2329 /***********************************************************************
2332 * Walks menu chain trying to find a menu pt maps to.
2334 static HMENU FASTCALL
2335 MenuPtMenu(HMENU Menu
, POINT Pt
)
2337 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2338 ROSMENUINFO MenuInfo
;
2339 ROSMENUITEMINFO ItemInfo
;
2343 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2348 /* try subpopup first (if any) */
2349 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2351 MenuInitRosMenuItemInfo(&ItemInfo
);
2352 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2353 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2354 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2356 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2359 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2363 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2366 /* check the current window (avoiding WM_HITTEST) */
2367 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2368 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2370 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2375 else if (HTSYSMENU
== Ht
)
2377 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2379 else if (HTMENU
== Ht
)
2381 Ret
= GetMenu(MenuInfo
.Wnd
);
2387 /***********************************************************************
2390 * Return TRUE if we can go on with menu tracking.
2392 static BOOL FASTCALL
2393 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2396 ROSMENUINFO MenuInfo
;
2400 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2404 if (IS_SYSTEM_MENU(&MenuInfo
))
2410 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2415 Index
= NO_SELECTED_ITEM
;
2418 if (NO_SELECTED_ITEM
== Index
)
2420 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2421 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2423 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2427 else if (MenuInfo
.FocusedItem
!= Index
)
2429 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2430 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2436 /******************************************************************************
2438 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2440 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2443 PROSMENUITEMINFO MenuItems
;
2445 i
= MenuInfo
->FocusedItem
;
2446 if (NO_SELECTED_ITEM
== i
)
2451 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2453 return NO_SELECTED_ITEM
;
2456 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2458 if (0 != (MenuItems
[i
].fType
& MF_MENUBARBREAK
))
2464 return NO_SELECTED_ITEM
;
2467 /******************************************************************************
2469 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2471 static UINT FASTCALL
2472 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2475 PROSMENUITEMINFO MenuItems
;
2477 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2479 return NO_SELECTED_ITEM
;
2482 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2484 return NO_SELECTED_ITEM
;
2487 /* Find the start of the column */
2489 for (i
= MenuInfo
->FocusedItem
;
2490 0 != i
&& 0 == (MenuItems
[i
].fType
& MF_MENUBARBREAK
);
2498 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2499 return NO_SELECTED_ITEM
;
2502 for (--i
; 0 != i
; --i
)
2504 if (MenuItems
[i
].fType
& MF_MENUBARBREAK
)
2510 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2511 DPRINT("ret %d.\n", i
);
2516 /***********************************************************************
2519 * Return the handle of the selected sub-popup menu (if any).
2521 static HMENU FASTCALL
2522 MenuGetSubPopup(HMENU Menu
)
2524 ROSMENUINFO MenuInfo
;
2525 ROSMENUITEMINFO ItemInfo
;
2527 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2528 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2533 MenuInitRosMenuItemInfo(&ItemInfo
);
2534 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2536 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2539 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2541 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2542 return ItemInfo
.hSubMenu
;
2545 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2549 /***********************************************************************
2552 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2554 static LRESULT FASTCALL
2555 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2557 ROSMENUINFO TopMenuInfo
;
2558 ROSMENUINFO MenuInfo
;
2560 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2562 return (LRESULT
) FALSE
;
2565 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2566 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2568 MDINEXTMENU NextMenu
;
2573 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2574 NextMenu
.hmenuNext
= NULL
;
2575 NextMenu
.hwndNext
= NULL
;
2576 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2578 DPRINT("%p [%p] -> %p [%p]\n",
2579 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2581 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2583 DWORD Style
= GetWindowLongW(Mt
->OwnerWnd
, GWL_STYLE
);
2584 NewWnd
= Mt
->OwnerWnd
;
2585 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2587 /* switch to the menu bar */
2589 if (0 != (Style
& WS_CHILD
)
2590 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2597 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2601 Id
= MenuInfo
.MenuItemCount
- 1;
2604 else if (0 != (Style
& WS_SYSMENU
))
2606 /* switch to the system menu */
2607 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2614 else /* application returned a new menu to switch to */
2616 NewMenu
= NextMenu
.hmenuNext
;
2617 NewWnd
= NextMenu
.hwndNext
;
2619 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2621 DWORD Style
= GetWindowLongW(NewWnd
, GWL_STYLE
);
2623 if (0 != (Style
& WS_SYSMENU
)
2624 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2626 /* get the real system menu */
2627 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2629 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2631 /* FIXME: Not sure what to do here;
2632 * perhaps try to track NewMenu as a popup? */
2634 DPRINT(" -- got confused.\n");
2644 if (NewMenu
!= Mt
->TopMenu
)
2646 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2648 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2650 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2654 if (NewWnd
!= Mt
->OwnerWnd
)
2656 Mt
->OwnerWnd
= NewWnd
;
2657 SetCapture(Mt
->OwnerWnd
);
2660 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2661 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2663 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2672 /***********************************************************************
2675 * The idea is not to show the popup if the next input message is
2676 * going to hide it anyway.
2678 static BOOL FASTCALL
2679 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2683 Msg
.hwnd
= Mt
->OwnerWnd
;
2685 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2686 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2691 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2692 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2694 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2695 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2696 if (WM_KEYDOWN
== Msg
.message
2697 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2699 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2706 /* failures go through this */
2707 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2712 /***********************************************************************
2715 * Handle a VK_ESCAPE key event in a menu.
2717 static BOOL FASTCALL
2718 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2720 BOOL EndMenu
= TRUE
;
2721 ROSMENUINFO MenuInfo
;
2722 HMENU MenuTmp
, MenuPrev
;
2724 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2726 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2727 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2729 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2731 /* close topmost popup */
2732 while (MenuTmp
!= Mt
->CurrentMenu
)
2735 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2738 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2740 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
2742 Mt
->CurrentMenu
= MenuPrev
;
2750 /***********************************************************************
2753 * Handle a VK_LEFT key event in a menu.
2755 static void FASTCALL
2756 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2758 ROSMENUINFO MenuInfo
;
2759 ROSMENUINFO TopMenuInfo
;
2760 ROSMENUINFO PrevMenuInfo
;
2761 HMENU MenuTmp
, MenuPrev
;
2764 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2766 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2771 /* Try to move 1 column left (if possible) */
2772 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
2774 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2776 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
2781 /* close topmost popup */
2782 while (MenuTmp
!= Mt
->CurrentMenu
)
2785 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2788 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
2792 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
2793 Mt
->CurrentMenu
= MenuPrev
;
2795 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2799 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
2801 /* move menu bar selection if no more popups are left */
2803 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
2805 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
2808 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
2810 /* A sublevel menu was displayed - display the next one
2811 * unless there is another displacement coming up */
2813 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
2814 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2816 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
2823 /***********************************************************************
2826 * Handle a VK_RIGHT key event in a menu.
2828 static void FASTCALL
2829 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
2832 ROSMENUINFO MenuInfo
;
2833 ROSMENUINFO CurrentMenuInfo
;
2836 DPRINT("MenuKeyRight called, cur %p, top %p.\n",
2837 Mt
->CurrentMenu
, Mt
->TopMenu
);
2839 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
2843 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
2845 /* If already displaying a popup, try to display sub-popup */
2847 MenuTmp
= Mt
->CurrentMenu
;
2848 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
2850 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
2853 /* if subpopup was displayed then we are done */
2854 if (MenuTmp
!= Mt
->CurrentMenu
)
2860 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
2865 /* Check to see if there's another column */
2866 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
2868 DPRINT("Going to %d.\n", NextCol
);
2869 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2871 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
2876 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
2878 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2880 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
2881 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
2888 /* try to move to the next item */
2889 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
2891 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
2894 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
2896 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
2897 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
2899 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
2906 /***********************************************************************
2909 * Find the menu item selected by a key press.
2910 * Return item id, -1 if none, -2 if we should close the menu.
2912 static UINT FASTCALL
2913 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2914 WCHAR Key
, BOOL ForceMenuChar
)
2916 ROSMENUINFO SysMenuInfo
;
2917 PROSMENUITEMINFO Items
, ItemInfo
;
2921 DPRINT("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
2923 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
2925 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
2927 MenuInfo
= &SysMenuInfo
;
2935 if (NULL
!= MenuInfo
)
2937 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
2941 if (! ForceMenuChar
)
2943 Key
= towupper(Key
);
2945 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
2947 if (IS_STRING_ITEM(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
2949 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
2952 p
= wcschr(p
+ 2, '&');
2954 while (NULL
!= p
&& L
'&' == p
[1]);
2955 if (NULL
!= p
&& (towupper(p
[1]) == Key
))
2963 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
2964 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
2965 if (2 == HIWORD(MenuChar
))
2967 return LOWORD(MenuChar
);
2969 if (1 == HIWORD(MenuChar
))
2978 /***********************************************************************
2981 * Menu tracking code.
2984 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
2985 HWND Wnd
, const RECT
*Rect
)
2988 ROSMENUINFO MenuInfo
;
2989 ROSMENUITEMINFO ItemInfo
;
2991 INT ExecutedMenuId
= -1;
2993 BOOL EnterIdleSent
= FALSE
;
2996 Mt
.CurrentMenu
= Menu
;
3002 DPRINT("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3003 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3004 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3007 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3012 if (0 != (Flags
& TPM_BUTTONDOWN
))
3014 /* Get the result in order to start the tracking or not */
3015 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3016 fEndMenu
= ! fRemove
;
3019 SetCapture(Mt
.OwnerWnd
);
3023 /* we have to keep the message in the queue until it's
3024 * clear that menu loop is not over yet. */
3028 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3030 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3034 /* remove the message from the queue */
3035 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3039 if (! EnterIdleSent
)
3041 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3042 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3043 EnterIdleSent
= TRUE
;
3044 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3050 /* check if EndMenu() tried to cancel us, by posting this message */
3051 if (WM_CANCELMODE
== Msg
.message
)
3053 /* we are now out of the loop */
3056 /* remove the message from the queue */
3057 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3059 /* break out of internal loop, ala ESCAPE */
3063 TranslateMessage(&Msg
);
3066 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3068 EnterIdleSent
= FALSE
;
3072 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3075 * Use the mouse coordinates in lParam instead of those in the MSG
3076 * struct to properly handle synthetic messages. They are already
3077 * in screen coordinates.
3079 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3080 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3082 /* Find a menu for this mouse event */
3083 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3087 /* no WM_NC... messages in captured state */
3089 case WM_RBUTTONDBLCLK
:
3090 case WM_RBUTTONDOWN
:
3091 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3096 case WM_LBUTTONDBLCLK
:
3097 case WM_LBUTTONDOWN
:
3098 /* If the message belongs to the menu, removes it from the queue */
3099 /* Else, end menu tracking */
3100 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3101 fEndMenu
= ! fRemove
;
3105 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3111 /* Check if a menu was selected by the mouse */
3114 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3116 /* End the loop if ExecutedMenuId is an item ID */
3117 /* or if the job was done (ExecutedMenuId = 0). */
3118 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3122 /* No menu was selected by the mouse */
3123 /* if the function was called by TrackPopupMenu, continue
3124 with the menu tracking. If not, stop it */
3125 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3132 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3136 } /* switch(Msg.message) - mouse */
3138 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3140 fRemove
= TRUE
; /* Keyboard messages are always removed */
3148 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3150 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3156 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3158 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3159 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3163 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3164 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3166 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3168 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3170 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3174 else /* otherwise try to move selection */
3176 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3182 MenuKeyLeft(&Mt
, Flags
);
3186 MenuKeyRight(&Mt
, Flags
);
3190 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3196 hi
.cbSize
= sizeof(HELPINFO
);
3197 hi
.iContextType
= HELPINFO_MENUITEM
;
3198 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3200 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3206 MenuInitRosMenuItemInfo(&ItemInfo
);
3207 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3208 MenuInfo
.FocusedItem
,
3211 hi
.iCtrlId
= ItemInfo
.wID
;
3217 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3220 hi
.hItemHandle
= Menu
;
3221 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3222 hi
.MousePos
= Msg
.pt
;
3223 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3230 break; /* WM_KEYDOWN */
3239 break; /* WM_SYSKEYDOWN */
3245 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3249 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3251 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3252 fEndMenu
= (ExecutedMenuId
!= -1);
3256 /* Hack to avoid control chars. */
3257 /* We will find a better way real soon... */
3258 if (Msg
.wParam
< 32)
3263 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3264 LOWORD(Msg
.wParam
), FALSE
);
3265 if ((UINT
) -2 == Pos
)
3269 else if ((UINT
) -1 == Pos
)
3275 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3276 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3277 fEndMenu
= (-1 != ExecutedMenuId
);
3281 } /* switch(msg.message) - kbd */
3285 DispatchMessageW(&Msg
);
3293 /* finally remove message from the queue */
3295 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3297 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3301 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3305 SetCapture(NULL
); /* release the capture */
3307 /* If dropdown is still painted and the close box is clicked on
3308 then the menu will be destroyed as part of the DispatchMessage above.
3309 This will then invalidate the menu handle in Mt.hTopMenu. We should
3310 check for this first. */
3311 if (IsMenu(Mt
.TopMenu
))
3313 if (IsWindow(Mt
.OwnerWnd
))
3315 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3317 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3319 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3321 DestroyWindow(MenuInfo
.Wnd
);
3322 MenuInfo
.Wnd
= NULL
;
3324 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3327 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3330 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3332 /* Reset the variable for hiding menu */
3333 MenuInfo
.TimeToHide
= FALSE
;
3334 MenuSetRosMenuInfo(&MenuInfo
);
3338 /* The return value is only used by TrackPopupMenu */
3339 return (-1 != ExecutedMenuId
) ? ExecutedMenuId
: 0;
3342 /***********************************************************************
3345 static BOOL FASTCALL
3346 MenuExitTracking(HWND Wnd
)
3348 DPRINT("hwnd=%p\n", hWnd
);
3350 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3357 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3359 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3360 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3362 DPRINT("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, pt
.x
, pt
.y
);
3366 /* map point to parent client coordinates */
3367 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3368 if (Parent
!= GetDesktopWindow())
3370 ScreenToClient(Parent
, &Pt
);
3373 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3374 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3375 MenuExitTracking(Wnd
);
3381 MenuTrackKbdMenuBar(HWND hWnd
, ULONG wParam
, ULONG Key
)
3385 /* FUNCTIONS *****************************************************************/
3388 MenuIsStringItem(ULONG TypeData)
3390 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3398 AppendMenuA(HMENU hMenu
,
3400 UINT_PTR uIDNewItem
,
3403 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3412 AppendMenuW(HMENU hMenu
,
3414 UINT_PTR uIDNewItem
,
3417 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3426 CheckMenuItem(HMENU hmenu
,
3430 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3438 CheckMenuRadioItem(HMENU hmenu
,
3455 return NtUserCreateMenu(FALSE
);
3463 CreatePopupMenu(VOID
)
3465 return NtUserCreateMenu(TRUE
);
3473 DeleteMenu(HMENU hMenu
,
3477 return NtUserDeleteMenu(hMenu
, uPosition
, uFlags
);
3485 DestroyMenu(HMENU hMenu
)
3487 return NtUserDestroyMenu(hMenu
);
3495 DrawMenuBar(HWND hWnd
)
3498 /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
3507 EnableMenuItem(HMENU hMenu
,
3511 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
3521 guii
.cbSize
= sizeof(GUITHREADINFO
);
3522 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
3524 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
3536 return NtUserGetMenu(hWnd
);
3544 GetMenuBarInfo(HWND hwnd
,
3549 return (BOOL
)NtUserGetMenuBarInfo(hwnd
, idObject
, idItem
, pmbi
);
3557 GetMenuCheckMarkDimensions(VOID
)
3559 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
3560 GetSystemMetrics(SM_CYMENUCHECK
)));
3568 GetMenuDefaultItem(HMENU hMenu
,
3572 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
3580 GetMenuInfo(HMENU hmenu
,
3586 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
3589 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
3590 mi
.cbSize
= sizeof(MENUINFO
);
3591 mi
.fMask
= lpcmi
->fMask
;
3593 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
3595 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
3604 GetMenuItemCount(HMENU Menu
)
3606 ROSMENUINFO MenuInfo
;
3608 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
3616 GetMenuItemID(HMENU hMenu
,
3619 ROSMENUITEMINFO mii
;
3621 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3622 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
3624 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
3629 if (NULL
!= mii
.hSubMenu
)
3650 LPMENUITEMINFOA lpmii
)
3666 LPMENUITEMINFOW lpmii
)
3677 GetMenuItemRect(HWND hWnd
,
3697 ROSMENUINFO MenuInfo
;
3698 ROSMENUITEMINFO mii
;
3700 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3701 mii
.fMask
= MIIM_STATE
| MIIM_TYPE
| MIIM_SUBMENU
;
3704 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
3709 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
3713 nSubItems
= MenuInfo
.MenuItemCount
;
3715 /* FIXME - ported from wine, does that work (0xff)? */
3716 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
3717 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
3719 return (UINT
)-1; /* Invalid submenu */
3722 /* FIXME - ported from wine, does that work? */
3723 return (mii
.fType
| mii
.fState
);
3775 mi
.cbSize
= sizeof(MENUITEMINFOW
);
3776 mi
.fMask
= MIIM_SUBMENU
;
3778 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
3780 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
3797 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
3799 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
3814 return NtUserHiliteMenuItem(hwnd
, hmenu
, uItemHilite
, uHilite
);
3827 UINT_PTR uIDNewItem
,
3831 mii
.cbSize
= sizeof(MENUITEMINFOA
);
3832 mii
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
;
3834 mii
.fState
= MFS_ENABLED
;
3836 if(uFlags
& MF_BITMAP
)
3838 mii
.fType
|= MFT_BITMAP
;
3840 else if(uFlags
& MF_OWNERDRAW
)
3842 mii
.fType
|= MFT_OWNERDRAW
;
3845 if(uFlags
& MF_RIGHTJUSTIFY
)
3847 mii
.fType
|= MFT_RIGHTJUSTIFY
;
3849 if(uFlags
& MF_MENUBREAK
)
3851 mii
.fType
|= MFT_MENUBREAK
;
3853 if(uFlags
& MF_MENUBARBREAK
)
3855 mii
.fType
|= MFT_MENUBARBREAK
;
3857 if(uFlags
& MF_DISABLED
)
3859 mii
.fState
|= MFS_DISABLED
;
3861 if(uFlags
& MF_GRAYED
)
3863 mii
.fState
|= MFS_GRAYED
;
3866 mii
.dwTypeData
= (LPSTR
)lpNewItem
;
3867 if(uFlags
& MF_POPUP
)
3869 mii
.fMask
|= MIIM_SUBMENU
;
3870 mii
.hSubMenu
= (HMENU
)uIDNewItem
;
3874 mii
.fMask
|= MIIM_ID
;
3875 mii
.wID
= (UINT
)uIDNewItem
;
3877 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)!(MF_BYPOSITION
& uFlags
), &mii
);
3890 LPCMENUITEMINFOA lpmii
)
3893 UNICODE_STRING MenuText
;
3895 BOOL CleanHeap
= FALSE
;
3898 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
3899 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
3901 RtlMoveMemory ( &mi
, lpmii
, lpmii
->cbSize
);
3903 /* copy the text string */
3904 if((mi
.fMask
& (MIIM_TYPE
| MIIM_STRING
)) &&
3905 (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
) && mi
.dwTypeData
)
3907 Status
= HEAP_strdupAtoW ( &mi
.dwTypeData
, (LPCSTR
)mi
.dwTypeData
, &mi
.cch
);
3908 if (!NT_SUCCESS (Status
))
3910 SetLastError (RtlNtStatusToDosError(Status
));
3913 RtlInitUnicodeString(&MenuText
, (PWSTR
)mi
.dwTypeData
);
3914 mi
.dwTypeData
= (LPWSTR
)&MenuText
;
3918 res
= NtUserInsertMenuItem(hMenu
, uItem
, fByPosition
, &mi
);
3920 if ( CleanHeap
) HEAP_free ( mi
.dwTypeData
);
3935 LPCMENUITEMINFOW lpmii
)
3938 UNICODE_STRING MenuText
;
3940 BOOL CleanHeap
= FALSE
;
3941 HANDLE hHeap
= RtlGetProcessHeap();
3942 mi
.hbmpItem
= (HBITMAP
)0;
3944 // while we could just pass 'lpmii' to win32k, we make a copy so that
3945 // if a bad user passes bad data, we crash his process instead of the
3948 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
3949 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
3951 memcpy(&mi
, lpmii
, lpmii
->cbSize
);
3953 /* copy the text string */
3954 if((mi
.fMask
& (MIIM_TYPE
| MIIM_STRING
)) &&
3955 (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
) && mi
.dwTypeData
)
3959 if(!RtlCreateUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
))
3961 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY
));
3964 mi
.dwTypeData
= (LPWSTR
)&MenuText
;
3965 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
3970 res
= NtUserInsertMenuItem(hMenu
, uItem
, fByPosition
, &mi
);
3972 if(CleanHeap
) RtlFreeHeap (hHeap
, 0, mi
.dwTypeData
);
3987 UINT_PTR uIDNewItem
,
3991 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3992 mii
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
;
3994 mii
.fState
= MFS_ENABLED
;
3996 if(uFlags
& MF_BITMAP
)
3998 mii
.fType
|= MFT_BITMAP
;
4000 else if(uFlags
& MF_OWNERDRAW
)
4002 mii
.fType
|= MFT_OWNERDRAW
;
4005 if(uFlags
& MF_RIGHTJUSTIFY
)
4007 mii
.fType
|= MFT_RIGHTJUSTIFY
;
4009 if(uFlags
& MF_MENUBREAK
)
4011 mii
.fType
|= MFT_MENUBREAK
;
4013 if(uFlags
& MF_MENUBARBREAK
)
4015 mii
.fType
|= MFT_MENUBARBREAK
;
4017 if(uFlags
& MF_DISABLED
)
4019 mii
.fState
|= MFS_DISABLED
;
4021 if(uFlags
& MF_GRAYED
)
4023 mii
.fState
|= MFS_GRAYED
;
4026 mii
.dwTypeData
= (LPWSTR
)lpNewItem
;
4027 mii
.cch
= (NULL
== lpNewItem
? 0 : wcslen(lpNewItem
));
4028 if(uFlags
& MF_POPUP
)
4030 mii
.fType
|= MF_POPUP
;
4031 mii
.fMask
|= MIIM_SUBMENU
;
4032 mii
.hSubMenu
= (HMENU
)uIDNewItem
;
4036 mii
.fMask
|= MIIM_ID
;
4037 mii
.wID
= (UINT
)uIDNewItem
;
4039 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)!(MF_BYPOSITION
& uFlags
), &mii
);
4051 ROSMENUINFO MenuInfo
;
4053 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4061 LoadMenuA(HINSTANCE hInstance
,
4064 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4065 if (Resource
== NULL
)
4069 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4077 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4079 return(LoadMenuIndirectW(lpMenuTemplate
));
4087 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4090 WORD version
, offset
;
4091 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4093 version
= GET_WORD(p
);
4098 case 0: /* standard format is version of 0 */
4099 offset
= GET_WORD(p
);
4100 p
+= sizeof(WORD
) + offset
;
4101 if (!(hMenu
= CreateMenu())) return 0;
4102 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4108 case 1: /* extended format is version of 1 */
4109 offset
= GET_WORD(p
);
4110 p
+= sizeof(WORD
) + offset
;
4111 if (!(hMenu
= CreateMenu())) return 0;
4112 if (!MENUEX_ParseResource(p
, hMenu
))
4114 DestroyMenu( hMenu
);
4119 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4129 LoadMenuW(HINSTANCE hInstance
,
4132 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4133 if (Resource
== NULL
)
4137 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4151 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4164 UINT_PTR uIDNewItem
,
4181 UINT_PTR uIDNewItem
,
4199 return NtUserRemoveMenu(hMenu
, uPosition
, uFlags
);
4210 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4224 return NtUserSetMenuDefaultItem(hMenu
, uItem
, fByPos
);
4239 if(lpcmi
->cbSize
!= sizeof(MENUINFO
))
4242 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4243 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4256 HBITMAP hBitmapUnchecked
,
4257 HBITMAP hBitmapChecked
)
4273 LPMENUITEMINFOA lpmii
)
4289 LPMENUITEMINFOW lpmii
)
4306 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4311 SetLastError(ERROR_INVALID_MENU_HANDLE
);
4314 return NtUserSetSystemMenu(hwnd
, hMenu
);
4330 CONST RECT
*prcRect
)
4336 tpm
.cbSize
= sizeof(TPMPARAMS
);
4337 tpm
.rcExclude
= *prcRect
;
4340 return (BOOL
)NtUserTrackPopupMenuEx(hMenu
, uFlags
, x
, y
, hWnd
,
4341 (prcRect
? &tpm
: NULL
));
4358 return (BOOL
)NtUserTrackPopupMenuEx(hmenu
, fuFlags
, x
, y
, hwnd
, lptpm
);
4367 SetMenuContextHelpId(HMENU hmenu
,
4368 DWORD dwContextHelpId
)
4370 return NtUserSetMenuContextHelpId(hmenu
, dwContextHelpId
);
4379 GetMenuContextHelpId(HMENU hmenu
)
4382 mi
.cbSize
= sizeof(ROSMENUINFO
);
4383 mi
.fMask
= MIM_HELPID
;
4385 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
4387 return mi
.dwContextHelpID
;
4449 LPCWSTR lpszNewItem
,