2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: user32/windows/menu.c
7 * PROGRAMMERS: Casper S. Hornstrup
11 /* INCLUDES ******************************************************************/
14 #include <wine/debug.h>
16 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
18 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
20 /* internal popup menu window messages */
22 #define MM_SETMENUHANDLE (WM_USER + 0)
23 #define MM_GETMENUHANDLE (WM_USER + 1)
25 /* internal flags for menu tracking */
27 #define TF_ENDMENU 0x10000
28 #define TF_SUSPENDPOPUP 0x20000
29 #define TF_SKIPREMOVE 0x40000
34 /* Internal MenuTrackMenu() flags */
35 #define TPM_INTERNAL 0xF0000000
36 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
37 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
40 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
42 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
44 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
45 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
46 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
48 #define IS_SYSTEM_MENU(MenuInfo) \
49 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
51 #define IS_SYSTEM_POPUP(MenuInfo) \
52 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
54 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
56 /* Use global popup window because there's no way 2 menus can
57 * be tracked at the same time. */
58 static HWND top_popup
;
59 static HMENU top_popup_hmenu
;
61 /* Flag set by EndMenu() to force an exit from menu tracking */
62 static BOOL fEndMenu
= FALSE
;
64 #define MENU_ITEM_HBMP_SPACE (5)
65 #define MENU_BAR_ITEMS_SPACE (12)
66 #define SEPARATOR_HEIGHT (5)
67 #define MENU_TAB_SPACE (8)
72 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
73 HMENU TopMenu
; /* initial menu */
74 HWND OwnerWnd
; /* where notifications are sent */
79 /*********************************************************************
80 * PopupMenu class descriptor
82 const struct builtin_class_descr POPUPMENU_builtin_class
=
85 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
86 (WNDPROC
) NULL
, /* FIXME - procA */
87 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
88 sizeof(MENUINFO
*), /* extra */
89 (LPCWSTR
) IDC_ARROW
, /* cursor */
90 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
94 #define GET_WORD(ptr) (*(WORD *)(ptr))
97 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
100 HFONT hMenuFont
= NULL
;
101 HFONT hMenuFontBold
= NULL
;
103 /* Dimension of the menu bitmaps */
104 static HBITMAP BmpSysMenu
= NULL
;
106 static SIZE MenuCharSize
;
108 /***********************************************************************
111 * Get full information about menu
114 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
116 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
117 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
119 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
122 /***********************************************************************
125 * Set full information about menu
128 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
130 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
131 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
133 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
136 /***********************************************************************
137 * MenuInitRosMenuItemInfo
139 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
142 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
144 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
145 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
148 /***********************************************************************
149 * MenuGetRosMenuItemInfo
151 * Get full information about a menu item
154 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
156 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
158 if (ItemInfo
->dwTypeData
!= NULL
)
160 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
164 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
165 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
166 ItemInfo
->dwTypeData
= NULL
;
168 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
174 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
177 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
178 ItemInfo
->cch
* sizeof(WCHAR
));
179 if (NULL
== ItemInfo
->dwTypeData
)
184 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
189 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
191 ItemInfo
->fMask
= Save_Mask
;
195 /***********************************************************************
196 * MenuSetRosMenuItemInfo
198 * Set selected information about a menu item, need to set the mask bits.
201 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
205 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
206 ItemInfo
->dwTypeData
!= NULL
)
208 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
210 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
215 /***********************************************************************
216 * MenuCleanupRosMenuItemInfo
218 * Cleanup after use of MenuGet/SetRosMenuItemInfo
221 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
223 if (ItemInfo
->dwTypeData
!= NULL
)
225 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
226 ItemInfo
->dwTypeData
= NULL
;
230 /***********************************************************************
231 * MenuGetAllRosMenuItemInfo
233 * Get full information about all menu items
236 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
240 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
241 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
245 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
246 if (NULL
== *ItemInfo
)
251 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
254 /***********************************************************************
255 * MenuCleanupAllRosMenuItemInfo
257 * Cleanup after use of MenuGetAllRosMenuItemInfo
260 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
262 HeapFree(GetProcessHeap(), 0, ItemInfo
);
265 /***********************************************************************
266 * MenuInitSysMenuPopup
268 * Grey the appropriate items in System menu.
270 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
278 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
279 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
280 gray
= ((style
& WS_MAXIMIZE
) != 0);
281 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
282 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
283 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
284 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
285 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
286 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
287 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
288 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
290 /* The menu item must keep its state if it's disabled */
292 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
294 /* Set default menu item */
295 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
296 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
297 else DefItem
= SC_CLOSE
;
299 mii
.cbSize
= sizeof(MENUITEMINFOW
);
300 mii
.fMask
|= MIIM_STATE
;
301 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
302 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
304 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
307 /******************************************************************************
309 * UINT MenuGetStartOfNextColumn(
310 * PROSMENUINFO MenuInfo)
312 *****************************************************************************/
313 static UINT
MenuGetStartOfNextColumn(
314 PROSMENUINFO MenuInfo
)
316 PROSMENUITEMINFO MenuItems
;
319 i
= MenuInfo
->FocusedItem
;
320 if ( i
== NO_SELECTED_ITEM
)
323 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
324 return NO_SELECTED_ITEM
;
326 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
327 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
330 return NO_SELECTED_ITEM
;
333 /******************************************************************************
335 * UINT MenuGetStartOfPrevColumn(
336 * PROSMENUINFO MenuInfo)
338 *****************************************************************************/
340 static UINT FASTCALL
MenuGetStartOfPrevColumn(
341 PROSMENUINFO MenuInfo
)
343 PROSMENUITEMINFO MenuItems
;
346 if (!MenuInfo
->FocusedItem
|| MenuInfo
->FocusedItem
== NO_SELECTED_ITEM
)
347 return NO_SELECTED_ITEM
;
349 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
350 return NO_SELECTED_ITEM
;
352 /* Find the start of the column */
353 for (i
= MenuInfo
->FocusedItem
;
354 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
362 MenuCleanupAllRosMenuItemInfo(MenuItems
);
363 return NO_SELECTED_ITEM
;
366 for (--i
; 0 != i
; --i
)
367 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
370 MenuCleanupAllRosMenuItemInfo(MenuItems
);
371 TRACE("ret %d.\n", i
);
376 /***********************************************************************
379 * Find a Sub menu. Return the position of the submenu, and modifies
380 * *hmenu in case it is found in another sub-menu.
381 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
383 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
387 ROSMENUITEMINFO item
;
388 if (((*hmenu
)==(HMENU
)0xffff) ||
389 (!MenuGetRosMenuInfo(&menu
, *hmenu
)))
390 return NO_SELECTED_ITEM
;
392 MenuInitRosMenuItemInfo(&item
);
393 for (i
= 0; i
< menu
.MenuItemCount
; i
++) {
394 if (! MenuGetRosMenuItemInfo(menu
.Self
, i
, &item
))
396 MenuCleanupRosMenuItemInfo(&item
);
397 return NO_SELECTED_ITEM
;
399 if (!(item
.fType
& MF_POPUP
)) continue;
400 if (item
.hSubMenu
== hSubTarget
) {
401 MenuCleanupRosMenuItemInfo(&item
);
405 HMENU hsubmenu
= item
.hSubMenu
;
406 UINT pos
= MenuFindSubMenu(&hsubmenu
, hSubTarget
);
407 if (pos
!= NO_SELECTED_ITEM
) {
413 MenuCleanupRosMenuItemInfo(&item
);
414 return NO_SELECTED_ITEM
;
417 /***********************************************************************
420 * Load the arrow bitmap. We can't do this from MenuInit since user32
421 * can also be used (and thus initialized) from text-mode.
424 MenuLoadBitmaps(VOID
)
426 /* Load system buttons bitmaps */
427 if (NULL
== BmpSysMenu
)
429 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
433 /***********************************************************************
436 * Draws popup magic glyphs (can be found in system menu).
439 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
442 HFONT hFont
, hOldFont
;
448 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
451 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
454 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
457 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
461 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
464 ZeroMemory(&lf
, sizeof(LOGFONTW
));
465 InflateRect(r
, -2, -2);
466 lf
.lfHeight
= r
->bottom
- r
->top
;
468 lf
.lfWeight
= FW_NORMAL
;
469 lf
.lfCharSet
= DEFAULT_CHARSET
;
470 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
471 hFont
= CreateFontIndirect(&lf
);
472 /* save font and text color */
473 hOldFont
= SelectObject(dc
, hFont
);
474 clrsave
= GetTextColor(dc
);
475 bkmode
= GetBkMode(dc
);
476 /* set color and drawing mode */
477 SetBkMode(dc
, TRANSPARENT
);
483 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
484 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
487 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
488 /* draw selected symbol */
489 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
490 /* restore previous settings */
491 SetTextColor(dc
, clrsave
);
492 SelectObject(dc
, hOldFont
);
493 SetBkMode(dc
, bkmode
);
497 /***********************************************************************
500 * Find the menu item selected by a key press.
501 * Return item id, -1 if none, -2 if we should close the menu.
503 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
504 WCHAR Key
, BOOL ForceMenuChar
)
506 ROSMENUINFO SysMenuInfo
;
507 PROSMENUITEMINFO Items
, ItemInfo
;
511 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
513 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
515 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
517 MenuInfo
= &SysMenuInfo
;
525 if (NULL
!= MenuInfo
)
527 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
531 if ( !ForceMenuChar
)
534 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
536 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
538 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
541 p
= strchrW (p
+ 2, '&');
543 while (p
!= NULL
&& p
[1] == '&');
544 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
549 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
550 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
551 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
552 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
557 /***********************************************************************
558 * MenuGetBitmapItemSize
560 * Get the size of a bitmap item.
562 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
565 HBITMAP bmp
= lpitem
->hbmpItem
;
567 size
->cx
= size
->cy
= 0;
569 /* check if there is a magic menu item associated with this item */
570 if (IS_MAGIC_BITMAP(bmp
))
572 switch((INT_PTR
) bmp
)
574 case (INT_PTR
)HBMMENU_CALLBACK
:
576 MEASUREITEMSTRUCT measItem
;
577 measItem
.CtlType
= ODT_MENU
;
579 measItem
.itemID
= lpitem
->wID
;
580 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
581 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
582 measItem
.itemData
= lpitem
->dwItemData
;
583 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
584 size
->cx
= measItem
.itemWidth
;
585 size
->cy
= measItem
.itemHeight
;
590 case (INT_PTR
) HBMMENU_SYSTEM
:
591 if (0 != lpitem
->dwItemData
)
593 bmp
= (HBITMAP
) lpitem
->dwItemData
;
597 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
598 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
599 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
600 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
601 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
602 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
603 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
604 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
605 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
606 /* FIXME: Why we need to subtract these magic values? */
607 /* to make them smaller than the menu bar? */
608 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
609 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
614 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
616 size
->cx
= bm
.bmWidth
;
617 size
->cy
= bm
.bmHeight
;
621 /***********************************************************************
624 * Draw a bitmap item.
626 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
627 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
633 int w
= rect
->right
- rect
->left
;
634 int h
= rect
->bottom
- rect
->top
;
637 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
640 /* Check if there is a magic menu item associated with this item */
641 if (IS_MAGIC_BITMAP(hbmToDraw
))
647 switch ((INT_PTR
)hbmToDraw
)
649 case (INT_PTR
)HBMMENU_SYSTEM
:
650 if (lpitem
->dwTypeData
)
652 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
653 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
657 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
659 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
660 /* only use right half of the bitmap */
661 bmp_xoffset
= bm
.bmWidth
/ 2;
662 bm
.bmWidth
-= bmp_xoffset
;
665 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
666 flags
= DFCS_CAPTIONRESTORE
;
668 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
670 flags
= DFCS_CAPTIONMIN
;
672 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
674 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
676 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
677 flags
= DFCS_CAPTIONCLOSE
;
679 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
680 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
682 case (INT_PTR
)HBMMENU_CALLBACK
:
684 DRAWITEMSTRUCT drawItem
;
686 drawItem
.CtlType
= ODT_MENU
;
688 drawItem
.itemID
= lpitem
->wID
;
689 drawItem
.itemAction
= odaction
;
690 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
691 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
692 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
693 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
694 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
695 drawItem
.hwndItem
= (HWND
)hmenu
;
697 drawItem
.rcItem
= *rect
;
698 drawItem
.itemData
= lpitem
->dwItemData
;
699 /* some applications make this assumption on the DC's origin */
700 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
701 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
702 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
703 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
708 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
709 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
710 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
711 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
712 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
715 InflateRect(&r
, -1, -1);
716 if (0 != (lpitem
->fState
& MF_HILITE
))
718 flags
|= DFCS_PUSHED
;
720 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
724 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
727 hdcMem
= CreateCompatibleDC( hdc
);
728 SelectObject( hdcMem
, bmp
);
730 /* handle fontsize > bitmap_height */
731 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
733 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
734 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
735 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
736 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
740 /***********************************************************************
743 * Calculate the size of the menu item and store it in lpitem->rect.
745 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
746 INT orgX
, INT orgY
, BOOL menuBar
)
749 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
752 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
754 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
756 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
758 if (lpitem
->fType
& MF_OWNERDRAW
)
760 MEASUREITEMSTRUCT mis
;
761 mis
.CtlType
= ODT_MENU
;
763 mis
.itemID
= lpitem
->wID
;
764 mis
.itemData
= lpitem
->dwItemData
;
765 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
767 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
768 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
769 * width of a menufont character to the width of an owner-drawn menu.
771 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
774 /* under at least win95 you seem to be given a standard
775 height for the menu and the height value is ignored */
776 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
778 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
780 TRACE("id=%04lx size=%dx%d\n",
781 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
785 if (lpitem
->fType
& MF_SEPARATOR
)
787 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
789 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
795 if (lpitem
->hbmpItem
)
800 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
801 /* Keep the size of the bitmap in callback mode to be able
802 * to draw it correctly */
803 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
804 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
805 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
807 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
808 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
810 MenuSetRosMenuInfo(MenuInfo
);
811 itemheight
= size
.cy
+ 2;
813 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
814 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
815 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
816 lpitem
->dxTab
= lpitem
->Rect
.right
;
817 lpitem
->Rect
.right
+= check_bitmap_width
;
818 } else /* hbmpItem & MenuBar */ {
819 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
820 lpitem
->Rect
.right
+= size
.cx
;
821 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
822 itemheight
= size
.cy
;
824 /* Special case: Minimize button doesn't have a space behind it. */
825 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
826 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
827 lpitem
->Rect
.right
-= 1;
831 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
832 lpitem
->Rect
.right
+= check_bitmap_width
;
833 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
834 lpitem
->dxTab
= lpitem
->Rect
.right
;
835 lpitem
->Rect
.right
+= check_bitmap_width
;
838 /* it must be a text item - unless it's the system menu */
839 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
840 HFONT hfontOld
= NULL
;
841 RECT rc
= lpitem
->Rect
;
842 LONG txtheight
, txtwidth
;
844 if ( lpitem
->fState
& MFS_DEFAULT
) {
845 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
848 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
849 DT_SINGLELINE
|DT_CALCRECT
);
850 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
851 itemheight
= max( max( itemheight
, txtheight
),
852 GetSystemMetrics( SM_CYMENU
) - 1);
853 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
855 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
858 int n
= (int)( p
- lpitem
->dwTypeData
);
859 /* Item contains a tab (only meaningful in popup menus) */
860 /* get text size before the tab */
861 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
862 DT_SINGLELINE
|DT_CALCRECT
);
863 txtwidth
= rc
.right
- rc
.left
;
864 p
+= 1; /* advance past the Tab */
865 /* get text size after the tab */
866 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
867 DT_SINGLELINE
|DT_CALCRECT
);
868 lpitem
->dxTab
+= txtwidth
;
869 txtheight
= max( txtheight
, tmpheight
);
870 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
871 tmprc
.right
- tmprc
.left
; /* space for the short cut */
873 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
874 DT_SINGLELINE
|DT_CALCRECT
);
875 txtwidth
= rc
.right
- rc
.left
;
876 lpitem
->dxTab
+= txtwidth
;
878 lpitem
->Rect
.right
+= 2 + txtwidth
;
879 itemheight
= max( itemheight
,
880 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
882 if (hfontOld
) SelectObject (hdc
, hfontOld
);
883 } else if( menuBar
) {
884 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
886 lpitem
->Rect
.bottom
+= itemheight
;
887 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
890 /***********************************************************************
891 * MenuPopupMenuCalcSize
893 * Calculate the size of a popup menu.
895 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
897 ROSMENUITEMINFO lpitem
;
900 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
902 MenuInfo
->Width
= MenuInfo
->Height
= 0;
903 if (MenuInfo
->MenuItemCount
== 0)
905 MenuSetRosMenuInfo(MenuInfo
);
910 SelectObject( hdc
, hMenuFont
);
915 MenuInfo
->maxBmpSize
.cx
= 0;
916 MenuInfo
->maxBmpSize
.cy
= 0;
918 MenuInitRosMenuItemInfo(&lpitem
);
919 while (start
< MenuInfo
->MenuItemCount
)
924 maxTab
= maxTabWidth
= 0;
926 /* Parse items until column break or end of menu */
927 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
929 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
931 MenuCleanupRosMenuItemInfo(&lpitem
);
932 MenuSetRosMenuInfo(MenuInfo
);
936 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
938 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
939 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
941 MenuCleanupRosMenuItemInfo(&lpitem
);
942 MenuSetRosMenuInfo(MenuInfo
);
945 // Not sure here,, The patch from wine removes this.
946 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
950 maxX
= max(maxX
, lpitem
.Rect
.right
);
951 orgY
= lpitem
.Rect
.bottom
;
952 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
954 maxTab
= max( maxTab
, lpitem
.dxTab
);
955 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
959 /* Finish the column (set all items to the largest width found) */
960 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
963 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
965 lpitem
.Rect
.right
= maxX
;
966 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
968 lpitem
.dxTab
= maxTab
;
970 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
974 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
977 MenuInfo
->Width
= maxX
;
979 /* space for 3d border */
980 MenuInfo
->Height
+= 2;
981 MenuInfo
->Width
+= 2;
983 MenuCleanupRosMenuItemInfo(&lpitem
);
984 MenuSetRosMenuInfo(MenuInfo
);
988 /***********************************************************************
989 * MenuMenuBarCalcSize
991 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
992 * height is off by 1 pixel which causes lengthy window relocations when
993 * active document window is maximized/restored.
995 * Calculate the size of the menu bar.
997 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
998 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1000 ROSMENUITEMINFO ItemInfo
;
1001 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1003 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1004 if (MenuInfo
->MenuItemCount
== 0) return;
1005 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1006 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1007 MenuInfo
->Height
= 0;
1008 maxY
= lprect
->top
+ 1;
1012 MenuInfo
->maxBmpSize
.cx
= 0;
1013 MenuInfo
->maxBmpSize
.cy
= 0;
1015 MenuInitRosMenuItemInfo(&ItemInfo
);
1016 while (start
< MenuInfo
->MenuItemCount
)
1018 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1020 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1023 orgX
= lprect
->left
;
1026 /* Parse items until line break or end of menu */
1027 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1029 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1031 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1033 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1034 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1035 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1037 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1041 if (ItemInfo
.Rect
.right
> lprect
->right
)
1043 if (i
!= start
) break;
1044 else ItemInfo
.Rect
.right
= lprect
->right
;
1046 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1047 orgX
= ItemInfo
.Rect
.right
;
1048 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1050 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1052 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1058 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1059 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1061 /* Finish the line (set all items to the largest height found) */
1064 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1066 ItemInfo
.Rect
.bottom
= maxY
;
1067 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1072 start
= i
; /* This works! */
1076 lprect
->bottom
= maxY
;
1077 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1078 MenuSetRosMenuInfo(MenuInfo
);
1082 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1083 /* the last item (if several lines, only move the last line) */
1084 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1086 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1089 orgY
= ItemInfo
.Rect
.top
;
1090 orgX
= lprect
->right
;
1091 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1097 if (ItemInfo
.Rect
.top
!= orgY
)
1099 break; /* Other line */
1101 if (orgX
<= ItemInfo
.Rect
.right
)
1103 break; /* Too far right already */
1105 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1106 ItemInfo
.Rect
.right
= orgX
;
1107 orgX
= ItemInfo
.Rect
.left
;
1108 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1109 if (helpPos
+ 1 <= i
&&
1110 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1112 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1118 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1121 /***********************************************************************
1124 * Draw a single menu item.
1126 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1127 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1131 BOOL flat_menu
= FALSE
;
1133 PWND Wnd
= ValidateHwnd(hWnd
);
1138 if (lpitem
->fType
& MF_SYSMENU
)
1140 if ( (Wnd
->style
& WS_MINIMIZE
))
1142 UserGetInsideRectNC(Wnd
, &rect
);
1143 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1144 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1149 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1150 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1154 if (lpitem
->fState
& MF_HILITE
)
1156 if(menuBar
&& !flat_menu
) {
1157 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1158 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1160 if (lpitem
->fState
& MF_GRAYED
)
1161 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1163 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1164 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1169 if (lpitem
->fState
& MF_GRAYED
)
1170 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1172 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1173 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1176 rect
= lpitem
->Rect
;
1178 if (lpitem
->fType
& MF_OWNERDRAW
)
1181 ** Experimentation under Windows reveals that an owner-drawn
1182 ** menu is given the rectangle which includes the space it requested
1183 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1184 ** and a popup-menu arrow. This is the value of lpitem->rect.
1185 ** Windows will leave all drawing to the application except for
1186 ** the popup-menu arrow. Windows always draws that itself, after
1187 ** the menu owner has finished drawing.
1191 dis
.CtlType
= ODT_MENU
;
1193 dis
.itemID
= lpitem
->wID
;
1194 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1196 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1197 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1198 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1199 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1200 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1203 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1204 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1205 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1206 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1208 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1209 /* Draw the popup-menu arrow */
1210 if (lpitem
->fType
& MF_POPUP
)
1213 CopyRect(&rectTemp
, &rect
);
1214 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1215 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1220 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1222 if (lpitem
->fState
& MF_HILITE
)
1226 InflateRect (&rect
, -1, -1);
1227 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1228 InflateRect (&rect
, 1, 1);
1229 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1234 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1236 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1240 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1242 SetBkMode( hdc
, TRANSPARENT
);
1244 /* vertical separator */
1245 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1252 rc
.bottom
= Height
- 3;
1255 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1256 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1257 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1258 LineTo( hdc
, rc
.left
, rc
.bottom
);
1259 SelectObject( hdc
, oldPen
);
1262 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1265 /* horizontal separator */
1266 if (lpitem
->fType
& MF_SEPARATOR
)
1273 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1276 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1277 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1278 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1279 LineTo( hdc
, rc
.right
, rc
.top
);
1280 SelectObject( hdc
, oldPen
);
1283 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1288 /* helper lines for debugging */
1289 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1290 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1291 SelectObject(hdc
, GetStockObject(DC_PEN
));
1292 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1293 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1294 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1300 INT y
= rect
.top
+ rect
.bottom
;
1302 int checked
= FALSE
;
1303 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1304 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1305 /* Draw the check mark
1308 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1310 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1311 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1312 lpitem
->hbmpUnchecked
;
1313 if (bm
) /* we have a custom bitmap */
1315 HDC hdcMem
= CreateCompatibleDC( hdc
);
1317 SelectObject( hdcMem
, bm
);
1318 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1319 check_bitmap_width
, check_bitmap_height
,
1320 hdcMem
, 0, 0, SRCCOPY
);
1324 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1327 CopyRect(&r
, &rect
);
1328 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1329 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1330 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1331 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1335 if ( lpitem
->hbmpItem
)
1338 CopyRect(&bmpRect
, &rect
);
1339 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1340 bmpRect
.left
+= check_bitmap_width
+ 2;
1341 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1343 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1344 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1347 /* Draw the popup-menu arrow */
1348 if (lpitem
->fType
& MF_POPUP
)
1351 CopyRect(&rectTemp
, &rect
);
1352 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1353 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1356 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1357 rect
.left
+= check_bitmap_width
;
1358 rect
.right
-= check_bitmap_width
;
1360 else if( lpitem
->hbmpItem
)
1361 { /* Draw the bitmap */
1362 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1365 /* process text if present */
1371 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1372 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1374 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1375 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1377 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1379 if ( lpitem
->fState
& MFS_DEFAULT
)
1381 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1385 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1386 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1389 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1392 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1393 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1397 if(lpitem
->fState
& MF_GRAYED
)
1399 if (!(lpitem
->fState
& MF_HILITE
) )
1401 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1402 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1403 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1404 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1406 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1409 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1411 /* paint the shortcut text */
1412 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1414 if (L
'\t' == Text
[i
])
1416 rect
.left
= lpitem
->dxTab
;
1417 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1421 rect
.right
= lpitem
->dxTab
;
1422 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1425 if (lpitem
->fState
& MF_GRAYED
)
1427 if (!(lpitem
->fState
& MF_HILITE
) )
1429 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1430 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1431 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1432 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1434 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1436 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1440 SelectObject (hdc
, hfontOld
);
1444 /***********************************************************************
1447 * Paint a popup menu.
1449 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1451 HBRUSH hPrevBrush
= 0;
1454 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1456 GetClientRect( hwnd
, &rect
);
1458 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1459 && (SelectObject( hdc
, hMenuFont
)))
1463 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1465 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1468 BOOL flat_menu
= FALSE
;
1469 ROSMENUINFO MenuInfo
;
1470 ROSMENUITEMINFO ItemInfo
;
1472 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1474 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1476 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1478 /* draw menu items */
1479 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1483 MenuInitRosMenuItemInfo(&ItemInfo
);
1485 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1487 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1489 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1490 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1494 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1498 SelectObject( hdc
, hPrevBrush
);
1503 /***********************************************************************
1506 * Paint a menu bar. Returns the height of the menu bar.
1507 * called from [windows/nonclient.c]
1509 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1514 HMENU hMenu
= GetMenu(hwnd
);
1516 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1518 return GetSystemMetrics(SM_CYMENU
);
1523 hfontOld
= SelectObject(hDC
, hMenuFont
);
1525 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1527 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1529 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1530 return lppop
.Height
;
1533 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1536 /***********************************************************************
1539 * Display a popup menu.
1541 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1542 INT x
, INT y
, INT xanchor
, INT yanchor
)
1544 ROSMENUINFO MenuInfo
;
1545 ROSMENUITEMINFO ItemInfo
;
1551 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1552 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1554 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1555 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1557 MenuInitRosMenuItemInfo(&ItemInfo
);
1558 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1560 ItemInfo
.fMask
|= MIIM_STATE
;
1561 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1562 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1564 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1565 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1568 /* store the owner for DrawItem */
1569 if (!IsWindow(hwndOwner
))
1571 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1574 MenuInfo
.WndOwner
= hwndOwner
;
1575 MenuSetRosMenuInfo(&MenuInfo
);
1577 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1579 /* adjust popup menu pos so that it fits within the desktop */
1581 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1582 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1584 /* FIXME: should use item rect */
1587 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1588 info
.cbSize
= sizeof(info
);
1589 GetMonitorInfoW( monitor
, &info
);
1591 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1592 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1594 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1595 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1597 if( x
+ width
> info
.rcMonitor
.right
)
1599 if( xanchor
&& x
>= width
- xanchor
)
1600 x
-= width
- xanchor
;
1602 if( x
+ width
> info
.rcMonitor
.right
)
1603 x
= info
.rcMonitor
.right
- width
;
1605 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
1607 if( y
+ height
> info
.rcMonitor
.bottom
)
1609 if( yanchor
&& y
>= height
+ yanchor
)
1610 y
-= height
+ yanchor
;
1612 if( y
+ height
> info
.rcMonitor
.bottom
)
1613 y
= info
.rcMonitor
.bottom
- height
;
1615 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
1617 /* NOTE: In Windows, top menu popup is not owned. */
1618 MenuInfo
.Wnd
= CreateWindowExW( 0, WC_MENU
, NULL
,
1619 WS_POPUP
, x
, y
, width
, height
,
1620 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1621 (LPVOID
) MenuInfo
.Self
);
1622 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1624 top_popup
= MenuInfo
.Wnd
;
1625 top_popup_hmenu
= hmenu
;
1628 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1630 /* Display the window */
1632 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1633 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1634 UpdateWindow( MenuInfo
.Wnd
);
1639 /***********************************************************************
1642 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1643 BOOL sendMenuSelect
, HMENU topmenu
)
1645 ROSMENUITEMINFO ItemInfo
;
1646 ROSMENUINFO TopMenuInfo
;
1649 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1651 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1652 if (hmenu
->FocusedItem
== wIndex
) return;
1653 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1654 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1656 top_popup
= hmenu
->Wnd
;
1657 top_popup_hmenu
= hmenu
->Self
;
1660 SelectObject( hdc
, hMenuFont
);
1662 MenuInitRosMenuItemInfo(&ItemInfo
);
1664 /* Clear previous highlighted item */
1665 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1667 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1669 ItemInfo
.fMask
|= MIIM_STATE
;
1670 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1671 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1673 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1674 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1678 /* Highlight new item (if any) */
1679 hmenu
->FocusedItem
= wIndex
;
1680 MenuSetRosMenuInfo(hmenu
);
1681 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1683 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1685 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1687 ItemInfo
.fMask
|= MIIM_STATE
;
1688 ItemInfo
.fState
|= MF_HILITE
;
1689 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1690 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1691 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1696 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1697 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1698 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1699 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1703 else if (sendMenuSelect
) {
1706 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1707 if (pos
!= NO_SELECTED_ITEM
)
1709 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1710 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1712 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1713 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1715 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1721 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1722 ReleaseDC(hmenu
->Wnd
, hdc
);
1725 /***********************************************************************
1728 * Moves currently selected item according to the Offset parameter.
1729 * If there is no selection then it should select the last item if
1730 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1732 static void FASTCALL
1733 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1736 ROSMENUITEMINFO ItemInfo
;
1739 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1741 /* Prevent looping */
1742 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1744 else if (Offset
< -1)
1746 else if (Offset
> 1)
1749 MenuInitRosMenuItemInfo(&ItemInfo
);
1751 OrigPos
= MenuInfo
->FocusedItem
;
1752 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1759 i
= MenuInfo
->FocusedItem
;
1766 /* Clip and wrap around */
1769 i
= MenuInfo
->MenuItemCount
- 1;
1771 else if (i
>= MenuInfo
->MenuItemCount
)
1775 /* If this is a good candidate; */
1776 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1777 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1779 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1780 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1783 } while (i
!= OrigPos
);
1786 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1790 // This breaks some test results. Should handle A2U if called!
1792 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1797 pWnd
= ValidateHwnd(Wnd
);
1802 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1807 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1813 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1814 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1818 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1819 return MA_NOACTIVATE
;
1824 BeginPaint(Wnd
, &ps
);
1825 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1830 case WM_PRINTCLIENT
:
1832 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1833 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1841 /* zero out global pointer in case resident popup window was destroyed. */
1842 if (Wnd
== top_popup
)
1845 top_popup_hmenu
= NULL
;
1848 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
1855 if (0 == GetWindowLongPtrA(Wnd
, 0))
1857 OutputDebugStringA("no menu to display\n");
1862 SetWindowLongPtrA(Wnd
, 0, 0);
1866 case MM_SETMENUHANDLE
:
1867 SetWindowLongPtrA(Wnd
, 0, wParam
);
1870 case MM_GETMENUHANDLE
:
1872 return GetWindowLongPtrA(Wnd
, 0);
1875 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1881 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1883 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
1886 pWnd
= ValidateHwnd(Wnd
);
1891 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1896 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1902 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1903 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1907 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1908 return MA_NOACTIVATE
;
1913 BeginPaint(Wnd
, &ps
);
1914 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1919 case WM_PRINTCLIENT
:
1921 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1922 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1930 /* zero out global pointer in case resident popup window was destroyed. */
1931 if (Wnd
== top_popup
)
1934 top_popup_hmenu
= NULL
;
1937 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
1944 if (0 == GetWindowLongPtrW(Wnd
, 0))
1946 OutputDebugStringA("no menu to display\n");
1951 SetWindowLongPtrW(Wnd
, 0, 0);
1955 case MM_SETMENUHANDLE
:
1956 SetWindowLongPtrW(Wnd
, 0, wParam
);
1959 case MM_GETMENUHANDLE
:
1961 return GetWindowLongPtrW(Wnd
, 0);
1964 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1970 /**********************************************************************
1971 * MENU_ParseResource
1973 * Parse a standard menu resource and add items to the menu.
1974 * Return a pointer to the end of the resource.
1976 * NOTE: flags is equivalent to the mtOption field
1978 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1987 flags
= GET_WORD(res
);
1989 /* remove MF_END flag before passing it to AppendMenu()! */
1990 end
= (flags
& MF_END
);
1991 if(end
) flags
^= MF_END
;
1993 res
+= sizeof(WORD
);
1994 if(!(flags
& MF_POPUP
))
1997 res
+= sizeof(WORD
);
2001 res
+= strlen(str
) + 1;
2003 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
2004 if (flags
& MF_POPUP
)
2006 hSubMenu
= CreatePopupMenu();
2007 if(!hSubMenu
) return NULL
;
2008 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
2011 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
2013 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
2015 else /* Not a popup */
2020 flags
= MF_SEPARATOR
;
2024 if (*(LPCWSTR
)str
== 0)
2025 flags
= MF_SEPARATOR
;
2028 if (flags
& MF_SEPARATOR
)
2030 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2031 flags
|= MF_GRAYED
| MF_DISABLED
;
2035 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2037 AppendMenuW(hMenu
, flags
, id
,
2038 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2045 /**********************************************************************
2046 * MENUEX_ParseResource
2048 * Parse an extended menu resource and add items to the menu.
2049 * Return a pointer to the end of the resource.
2051 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2057 mii
.cbSize
= sizeof(mii
);
2058 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
2059 mii
.fType
= GET_DWORD(res
);
2060 res
+= sizeof(DWORD
);
2061 mii
.fState
= GET_DWORD(res
);
2062 res
+= sizeof(DWORD
);
2063 mii
.wID
= GET_DWORD(res
);
2064 res
+= sizeof(DWORD
);
2065 resinfo
= GET_WORD(res
);
2066 res
+= sizeof(WORD
);
2067 /* Align the text on a word boundary. */
2068 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2069 mii
.dwTypeData
= (LPWSTR
) res
;
2070 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2071 /* Align the following fields on a dword boundary. */
2072 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2074 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2075 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2077 if (resinfo
& 1) { /* Pop-up? */
2078 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2079 res
+= sizeof(DWORD
);
2080 mii
.hSubMenu
= CreatePopupMenu();
2083 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2084 DestroyMenu(mii
.hSubMenu
);
2087 mii
.fMask
|= MIIM_SUBMENU
;
2088 mii
.fType
|= MF_POPUP
;
2089 mii
.wID
= (UINT
) mii
.hSubMenu
;
2091 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
2093 mii
.fType
|= MF_SEPARATOR
;
2095 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2096 } while (!(resinfo
& MF_END
));
2101 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2103 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2104 LRESULT Result
= (LRESULT
)hmenu
;
2105 MENUINFO menuinfo
= {0};
2106 MENUITEMINFOW info
= {0};
2108 // removing space for checkboxes from menu
2109 menuinfo
.cbSize
= sizeof(menuinfo
);
2110 menuinfo
.fMask
= MIM_STYLE
;
2111 GetMenuInfo(hmenu
, &menuinfo
);
2112 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2113 SetMenuInfo(hmenu
, &menuinfo
);
2115 // adding bitmaps to menu items
2116 info
.cbSize
= sizeof(info
);
2117 info
.fMask
|= MIIM_BITMAP
;
2118 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2119 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2120 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2121 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2122 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2123 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2124 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2125 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2127 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2134 NONCLIENTMETRICSW ncm
;
2136 /* get the menu font */
2137 if(!hMenuFont
|| !hMenuFontBold
)
2139 ncm
.cbSize
= sizeof(ncm
);
2140 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2142 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2146 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2147 if(hMenuFont
== NULL
)
2149 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2153 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2154 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2155 if(hMenuFontBold
== NULL
)
2157 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2158 DeleteObject(hMenuFont
);
2172 DeleteObject(hMenuFont
);
2178 DeleteObject(hMenuFontBold
);
2179 hMenuFontBold
= NULL
;
2183 /***********************************************************************
2184 * DrawMenuBarTemp (USER32.@)
2188 * called by W98SE desk.cpl Control Panel Applet
2190 * Not 100% sure about the param names, but close.
2195 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2197 ROSMENUINFO MenuInfo
;
2198 ROSMENUITEMINFO ItemInfo
;
2200 HFONT FontOld
= NULL
;
2201 BOOL flat_menu
= FALSE
;
2203 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2207 Menu
= GetMenu(Wnd
);
2215 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2217 return GetSystemMetrics(SM_CYMENU
);
2220 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2222 FontOld
= SelectObject(DC
, Font
);
2224 if (0 == MenuInfo
.Height
)
2226 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2229 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2231 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2233 SelectObject(DC
, GetStockObject(DC_PEN
));
2234 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2235 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2236 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2238 if (0 == MenuInfo
.MenuItemCount
)
2240 SelectObject(DC
, FontOld
);
2241 return GetSystemMetrics(SM_CYMENU
);
2244 MenuInitRosMenuItemInfo(&ItemInfo
);
2245 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2247 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2249 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2250 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2253 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2255 SelectObject(DC
, FontOld
);
2257 return MenuInfo
.Height
;
2260 /***********************************************************************
2263 * Display the sub-menu of the selected item of this menu.
2264 * Return the handle of the submenu, or menu if no submenu to display.
2266 static HMENU FASTCALL
2267 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2269 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2271 ROSMENUITEMINFO ItemInfo
;
2272 ROSMENUINFO SubMenuInfo
;
2276 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2278 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2280 return MenuInfo
->Self
;
2283 MenuInitRosMenuItemInfo(&ItemInfo
);
2284 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2286 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2287 return MenuInfo
->Self
;
2289 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2291 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2292 return MenuInfo
->Self
;
2295 /* message must be sent before using item,
2296 because nearly everything may be changed by the application ! */
2298 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2299 if (0 == (Flags
& TPM_NONOTIFY
))
2301 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2302 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2305 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2307 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2308 return MenuInfo
->Self
;
2310 Rect
= ItemInfo
.Rect
;
2312 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2313 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2315 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2317 Dc
= GetDC(MenuInfo
->Wnd
);
2321 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2324 SelectObject(Dc
, hMenuFont
);
2325 ItemInfo
.fMask
|= MIIM_STATE
;
2326 ItemInfo
.fState
|= MF_HILITE
;
2327 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2328 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2329 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2330 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2333 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2334 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2336 ItemInfo
.Rect
= Rect
;
2339 ItemInfo
.fMask
|= MIIM_STATE
;
2340 ItemInfo
.fState
|= MF_MOUSESELECT
;
2341 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2343 if (IS_SYSTEM_MENU(MenuInfo
))
2345 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2346 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2348 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2349 Rect
.top
= Rect
.bottom
;
2350 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2351 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2355 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2356 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2358 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2359 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2360 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2361 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2362 - GetSystemMetrics(SM_CYBORDER
);
2366 Rect
.left
+= ItemInfo
.Rect
.left
;
2367 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2368 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2369 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2373 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2374 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2375 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2377 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2380 Ret
= ItemInfo
.hSubMenu
;
2381 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2386 /**********************************************************************
2389 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2391 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2393 void MENU_EndMenu( HWND hwnd
)
2395 ROSMENUINFO MenuInfo
;
2397 if (top_popup_hmenu
)
2398 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2399 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2402 /***********************************************************************
2405 * Hide the sub-popup menus of this menu.
2407 static void FASTCALL
2408 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2409 BOOL SendMenuSelect
, UINT wFlags
)
2411 ROSMENUINFO SubMenuInfo
;
2412 ROSMENUITEMINFO ItemInfo
;
2414 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2416 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2418 MenuInitRosMenuItemInfo(&ItemInfo
);
2419 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2420 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2421 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2422 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2424 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2427 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2428 ItemInfo
.fMask
|= MIIM_STATE
;
2429 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2430 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2432 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2433 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2434 DestroyWindow(SubMenuInfo
.Wnd
);
2435 SubMenuInfo
.Wnd
= NULL
;
2436 MenuSetRosMenuInfo(&SubMenuInfo
);
2438 if (!(wFlags
& TPM_NONOTIFY
))
2439 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2440 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2445 /***********************************************************************
2446 * MenuSwitchTracking
2448 * Helper function for menu navigation routines.
2450 static void FASTCALL
2451 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2453 ROSMENUINFO TopMenuInfo
;
2455 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2457 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2458 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2459 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2461 /* both are top level menus (system and menu-bar) */
2462 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2463 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2464 Mt
->TopMenu
= PtMenuInfo
->Self
;
2468 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2471 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2474 /***********************************************************************
2475 * MenuExecFocusedItem
2477 * Execute a menu item (for instance when user pressed Enter).
2478 * Return the wID of the executed item. Otherwise, -1 indicating
2479 * that no menu item was executed, -2 if a popup is shown;
2480 * Have to receive the flags for the TrackPopupMenu options to avoid
2481 * sending unwanted message.
2485 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2487 ROSMENUITEMINFO ItemInfo
;
2490 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2492 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2497 MenuInitRosMenuItemInfo(&ItemInfo
);
2498 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2500 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2504 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2506 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2508 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2509 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2511 /* If TPM_RETURNCMD is set you return the id, but
2512 do not send a message to the owner */
2513 if (0 == (Flags
& TPM_RETURNCMD
))
2515 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2517 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2518 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2522 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2523 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2524 MenuInfo
->FocusedItem
,
2525 (LPARAM
)MenuInfo
->Self
);
2527 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2531 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2537 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2544 /***********************************************************************
2547 * Return TRUE if we can go on with menu tracking.
2549 static BOOL FASTCALL
2550 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2553 ROSMENUINFO MenuInfo
;
2554 ROSMENUITEMINFO Item
;
2556 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2560 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2564 if (IS_SYSTEM_MENU(&MenuInfo
))
2570 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2572 MenuInitRosMenuItemInfo(&Item
);
2573 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2575 MenuCleanupRosMenuItemInfo(&Item
);
2579 if (!(Item
.fType
& MF_SEPARATOR
) &&
2580 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2582 if (MenuInfo
.FocusedItem
!= Index
)
2584 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2587 /* If the popup menu is not already "popped" */
2588 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2590 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2594 MenuCleanupRosMenuItemInfo(&Item
);
2599 /* else the click was on the menu bar, finish the tracking */
2604 /***********************************************************************
2607 * Return the value of MenuExecFocusedItem if
2608 * the selected item was not a popup. Else open the popup.
2609 * A -1 return value indicates that we go on with menu tracking.
2613 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2616 ROSMENUINFO MenuInfo
;
2617 ROSMENUITEMINFO ItemInfo
;
2619 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2624 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2629 if (! IS_SYSTEM_MENU(&MenuInfo
))
2631 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2633 MenuInitRosMenuItemInfo(&ItemInfo
);
2634 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2635 MenuInfo
.FocusedItem
== Id
)
2637 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2639 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2640 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2641 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2643 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2645 /* If we are dealing with the top-level menu */
2646 /* and this is a click on an already "popped" item: */
2647 /* Stop the menu tracking and close the opened submenus */
2648 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2650 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2654 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2655 MenuInfo
.TimeToHide
= TRUE
;
2656 MenuSetRosMenuInfo(&MenuInfo
);
2662 /***********************************************************************
2665 * Walks menu chain trying to find a menu pt maps to.
2667 static HMENU FASTCALL
2668 MenuPtMenu(HMENU Menu
, POINT Pt
)
2670 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2671 ROSMENUINFO MenuInfo
;
2672 ROSMENUITEMINFO ItemInfo
;
2676 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2681 /* try subpopup first (if any) */
2682 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2684 MenuInitRosMenuItemInfo(&ItemInfo
);
2685 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2686 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2687 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2689 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2692 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2696 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2699 /* check the current window (avoiding WM_HITTEST) */
2700 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2701 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2703 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2708 else if (HTSYSMENU
== Ht
)
2710 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2712 else if (HTMENU
== Ht
)
2714 Ret
= GetMenu(MenuInfo
.Wnd
);
2720 /***********************************************************************
2723 * Return TRUE if we can go on with menu tracking.
2725 static BOOL FASTCALL
2726 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2729 ROSMENUINFO MenuInfo
;
2730 ROSMENUITEMINFO ItemInfo
;
2734 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2738 if (IS_SYSTEM_MENU(&MenuInfo
))
2744 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2749 Index
= NO_SELECTED_ITEM
;
2752 if (NO_SELECTED_ITEM
== Index
)
2754 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2755 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2757 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2761 else if (MenuInfo
.FocusedItem
!= Index
)
2763 MenuInitRosMenuItemInfo(&ItemInfo
);
2764 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2765 !(ItemInfo
.fType
& MF_SEPARATOR
))
2767 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2768 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2769 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2771 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2777 /***********************************************************************
2780 * Return the handle of the selected sub-popup menu (if any).
2782 static HMENU FASTCALL
2783 MenuGetSubPopup(HMENU Menu
)
2785 ROSMENUINFO MenuInfo
;
2786 ROSMENUITEMINFO ItemInfo
;
2788 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2789 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2794 MenuInitRosMenuItemInfo(&ItemInfo
);
2795 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2797 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2800 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2802 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2803 return ItemInfo
.hSubMenu
;
2806 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2810 /***********************************************************************
2813 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2815 static LRESULT FASTCALL
2816 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2818 ROSMENUINFO TopMenuInfo
;
2819 ROSMENUINFO MenuInfo
;
2821 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2823 return (LRESULT
) FALSE
;
2826 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2827 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2829 MDINEXTMENU NextMenu
;
2834 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2835 NextMenu
.hmenuNext
= NULL
;
2836 NextMenu
.hwndNext
= NULL
;
2837 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2839 TRACE("%p [%p] -> %p [%p]\n",
2840 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2842 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2844 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2845 NewWnd
= Mt
->OwnerWnd
;
2846 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2848 /* switch to the menu bar */
2850 if (0 != (Style
& WS_CHILD
)
2851 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2858 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2862 Id
= MenuInfo
.MenuItemCount
- 1;
2865 else if (0 != (Style
& WS_SYSMENU
))
2867 /* switch to the system menu */
2868 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2875 else /* application returned a new menu to switch to */
2877 NewMenu
= NextMenu
.hmenuNext
;
2878 NewWnd
= NextMenu
.hwndNext
;
2880 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2882 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2884 if (0 != (Style
& WS_SYSMENU
)
2885 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2887 /* get the real system menu */
2888 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2890 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2892 /* FIXME: Not sure what to do here;
2893 * perhaps try to track NewMenu as a popup? */
2895 WARN(" -- got confused.\n");
2905 if (NewMenu
!= Mt
->TopMenu
)
2907 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2909 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2911 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2915 if (NewWnd
!= Mt
->OwnerWnd
)
2917 Mt
->OwnerWnd
= NewWnd
;
2918 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
2919 SetCapture(Mt
->OwnerWnd
); // 2
2922 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2923 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2925 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2934 /***********************************************************************
2937 * The idea is not to show the popup if the next input message is
2938 * going to hide it anyway.
2940 static BOOL FASTCALL
2941 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
2945 msg
.hwnd
= Mt
->OwnerWnd
;
2947 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
2948 // Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
2953 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2954 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2956 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2957 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2958 if( msg
.message
== WM_KEYDOWN
&&
2959 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2961 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2967 /* failures go through this */
2968 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2972 /***********************************************************************
2975 * Handle a VK_ESCAPE key event in a menu.
2977 static BOOL FASTCALL
2978 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2980 BOOL EndMenu
= TRUE
;
2981 ROSMENUINFO MenuInfo
;
2982 HMENU MenuTmp
, MenuPrev
;
2984 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2986 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2987 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2989 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2991 /* close topmost popup */
2992 while (MenuTmp
!= Mt
->CurrentMenu
)
2995 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2998 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3000 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3002 Mt
->CurrentMenu
= MenuPrev
;
3010 /***********************************************************************
3013 * Handle a VK_LEFT key event in a menu.
3015 static void FASTCALL
3016 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3018 ROSMENUINFO MenuInfo
;
3019 ROSMENUINFO TopMenuInfo
;
3020 ROSMENUINFO PrevMenuInfo
;
3021 HMENU MenuTmp
, MenuPrev
;
3024 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3026 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3031 /* Try to move 1 column left (if possible) */
3032 if ( (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)) != NO_SELECTED_ITEM
)
3034 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3036 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3041 /* close topmost popup */
3042 while (MenuTmp
!= Mt
->CurrentMenu
)
3045 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3048 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3052 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3053 Mt
->CurrentMenu
= MenuPrev
;
3055 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3059 if ((MenuPrev
== Mt
->TopMenu
) && !(TopMenuInfo
.Flags
& MF_POPUP
))
3061 /* move menu bar selection if no more popups are left */
3063 if (!MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3065 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3068 if (MenuPrev
!= MenuTmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3070 /* A sublevel menu was displayed - display the next one
3071 * unless there is another displacement coming up */
3073 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3074 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3076 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3083 /***********************************************************************
3086 * Handle a VK_RIGHT key event in a menu.
3088 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3091 ROSMENUINFO MenuInfo
;
3092 ROSMENUINFO CurrentMenuInfo
;
3095 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3096 Mt
->CurrentMenu
, Mt
->TopMenu
);
3098 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3099 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3101 /* If already displaying a popup, try to display sub-popup */
3103 hmenutmp
= Mt
->CurrentMenu
;
3104 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3106 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3109 /* if subpopup was displayed then we are done */
3110 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3113 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3118 /* Check to see if there's another column */
3119 if ( (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)) != NO_SELECTED_ITEM
)
3121 TRACE("Going to %d.\n", NextCol
);
3122 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3124 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3129 if (!(MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3131 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3133 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3134 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3141 /* try to move to the next item */
3142 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3143 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3145 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3147 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3148 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3150 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3157 /***********************************************************************
3160 * Menu tracking code.
3162 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3163 HWND hwnd
, const RECT
*lprect
)
3166 ROSMENUINFO MenuInfo
;
3167 ROSMENUITEMINFO ItemInfo
;
3169 INT executedMenuId
= -1;
3172 BOOL enterIdleSent
= FALSE
;
3175 mt
.CurrentMenu
= hmenu
;
3181 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3182 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3183 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3187 WARN("Invalid menu handle %p\n", hmenu
);
3188 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3193 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3198 if (wFlags
& TPM_BUTTONDOWN
)
3200 /* Get the result in order to start the tracking or not */
3201 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3202 fEndMenu
= !fRemove
;
3205 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3207 /* owner may not be visible when tracking a popup, so use the menu itself */
3208 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3209 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3210 SetCapture(capture_win
); // 2
3214 BOOL ErrorExit
= FALSE
;
3215 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, otMenu
);
3216 if (!menu
) /* sometimes happens if I do a window manager close */
3219 /* we have to keep the message in the queue until it's
3220 * clear that menu loop is not over yet. */
3224 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3226 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3227 /* remove the message from the queue */
3228 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3233 if (!ValidateHwnd(mt
.OwnerWnd
) || !ValidateHwnd(MenuInfo
.Wnd
))
3235 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3240 HWND win
= MenuInfo
.Flags
& MF_POPUP
? MenuInfo
.Wnd
: NULL
;
3241 enterIdleSent
= TRUE
;
3242 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3248 if (ErrorExit
) break; // Gracefully dropout.
3250 /* check if EndMenu() tried to cancel us, by posting this message */
3251 if (msg
.message
== WM_CANCELMODE
)
3253 /* we are now out of the loop */
3256 /* remove the message from the queue */
3257 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3259 /* break out of internal loop, ala ESCAPE */
3263 TranslateMessage( &msg
);
3266 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3267 enterIdleSent
=FALSE
;
3270 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3273 * Use the mouse coordinates in lParam instead of those in the MSG
3274 * struct to properly handle synthetic messages. They are already
3275 * in screen coordinates.
3277 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3278 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3280 /* Find a menu for this mouse event */
3281 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3285 /* no WM_NC... messages in captured state */
3287 case WM_RBUTTONDBLCLK
:
3288 case WM_RBUTTONDOWN
:
3289 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3291 case WM_LBUTTONDBLCLK
:
3292 case WM_LBUTTONDOWN
:
3293 /* If the message belongs to the menu, removes it from the queue */
3294 /* Else, end menu tracking */
3295 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3296 fEndMenu
= !fRemove
;
3300 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3303 /* Check if a menu was selected by the mouse */
3306 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3307 TRACE("executedMenuId %d\n", executedMenuId
);
3309 /* End the loop if executedMenuId is an item ID */
3310 /* or if the job was done (executedMenuId = 0). */
3311 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3313 /* No menu was selected by the mouse */
3314 /* if the function was called by TrackPopupMenu, continue
3315 with the menu tracking. If not, stop it */
3317 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3322 /* the selected menu item must be changed every time */
3323 /* the mouse moves. */
3326 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3328 } /* switch(msg.message) - mouse */
3330 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3332 fRemove
= TRUE
; /* Keyboard messages are always removed */
3346 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3348 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
3349 NO_SELECTED_ITEM
, FALSE
, 0 );
3350 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3351 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3356 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3357 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3359 if (!(MenuInfo
.Flags
& MF_POPUP
))
3361 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3362 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3364 else /* otherwise try to move selection */
3365 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3366 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3371 MenuKeyLeft( &mt
, wFlags
);
3375 MenuKeyRight( &mt
, wFlags
);
3379 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3385 hi
.cbSize
= sizeof(HELPINFO
);
3386 hi
.iContextType
= HELPINFO_MENUITEM
;
3387 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3389 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
)
3393 MenuInitRosMenuItemInfo(&ItemInfo
);
3394 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3395 MenuInfo
.FocusedItem
,
3398 hi
.iCtrlId
= ItemInfo
.wID
;
3404 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3407 hi
.hItemHandle
= hmenu
;
3408 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3409 hi
.MousePos
= msg
.pt
;
3410 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3417 break; /* WM_KEYDOWN */
3424 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3425 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3427 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3428 fEndMenu
= (executedMenuId
!= -2);
3432 /* Hack to avoid control chars. */
3433 /* We will find a better way real soon... */
3434 if (msg
.wParam
< 32) break;
3436 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3437 LOWORD(msg
.wParam
), FALSE
);
3438 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3439 else if (pos
== (UINT
)-1) MessageBeep(0);
3442 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3444 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3445 fEndMenu
= (executedMenuId
!= -2);
3449 } /* switch(msg.message) - kbd */
3453 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3454 DispatchMessageW( &msg
);
3458 if (!fEndMenu
) fRemove
= TRUE
;
3460 /* finally remove message from the queue */
3462 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3463 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3464 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3467 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3468 SetCapture(NULL
); /* release the capture */
3470 /* If dropdown is still painted and the close box is clicked on
3471 then the menu will be destroyed as part of the DispatchMessage above.
3472 This will then invalidate the menu handle in mt.hTopMenu. We should
3473 check for this first. */
3474 if( IsMenu( mt
.TopMenu
) )
3476 if (IsWindow(mt
.OwnerWnd
))
3478 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3480 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3482 if (MenuInfo
.Flags
& MF_POPUP
)
3484 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3485 DestroyWindow(MenuInfo
.Wnd
);
3486 MenuInfo
.Wnd
= NULL
;
3488 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3489 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3490 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3493 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3496 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3499 /* Reset the variable for hiding menu */
3500 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3502 MenuInfo
.TimeToHide
= FALSE
;
3503 MenuSetRosMenuInfo(&MenuInfo
);
3507 /* The return value is only used by TrackPopupMenu */
3508 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3509 if (executedMenuId
== -1) executedMenuId
= 0;
3510 return executedMenuId
;
3513 /***********************************************************************
3516 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3518 ROSMENUINFO MenuInfo
;
3520 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3524 /* This makes the menus of applications built with Delphi work.
3525 * It also enables menus to be displayed in more than one window,
3526 * but there are some bugs left that need to be fixed in this case.
3528 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
3530 MenuInfo
.Wnd
= hWnd
;
3531 MenuSetRosMenuInfo(&MenuInfo
);
3534 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3535 if (!(wFlags
& TPM_NONOTIFY
))
3536 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3538 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3540 if (!(wFlags
& TPM_NONOTIFY
))
3542 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3543 /* If an app changed/recreated menu bar entries in WM_INITMENU
3544 * menu sizes will be recalculated once the menu created/shown.
3547 if (!MenuInfo
.Height
)
3549 /* app changed/recreated menu bar entries in WM_INITMENU
3550 Recalculate menu sizes else clicks will not work */
3551 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3552 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3557 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
3559 MenuInfo
.Flags
& MF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
3563 /***********************************************************************
3566 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
3568 TRACE("hwnd=%p\n", hWnd
);
3570 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
3571 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
3574 top_popup_hmenu
= NULL
;
3578 /***********************************************************************
3579 * MenuTrackMouseMenuBar
3581 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3583 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3585 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3586 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3588 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3592 /* map point to parent client coordinates */
3593 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3594 if (Parent
!= GetDesktopWindow())
3596 ScreenToClient(Parent
, &pt
);
3599 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3600 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3601 MenuExitTracking(hWnd
, FALSE
);
3606 /***********************************************************************
3607 * MenuTrackKbdMenuBar
3609 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3611 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3613 UINT uItem
= NO_SELECTED_ITEM
;
3615 ROSMENUINFO MenuInfo
;
3616 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3618 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3620 /* find window that has a menu */
3622 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3623 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3624 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3626 /* check if we have to track a system menu */
3628 hTrackMenu
= GetMenu( hwnd
);
3629 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3631 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3632 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3634 wParam
|= HTSYSMENU
; /* prevent item lookup */
3637 if (!IsMenu( hTrackMenu
)) return;
3639 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3641 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3646 if( wChar
&& wChar
!= ' ' )
3648 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3649 if ( uItem
>= (UINT
)(-2) )
3651 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3652 /* schedule end of menu tracking */
3653 wFlags
|= TF_ENDMENU
;
3658 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3660 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
3662 if( uItem
== NO_SELECTED_ITEM
)
3663 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3665 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
3669 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3670 MenuExitTracking( hwnd
, FALSE
);
3673 /**********************************************************************
3674 * TrackPopupMenuEx (USER32.@)
3676 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
3677 HWND Wnd
, LPTPMPARAMS Tpm
)
3680 ROSMENUINFO MenuInfo
;
3684 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3689 if (!ValidateHwnd(Wnd
))
3694 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
3695 if (IsWindow(MenuInfo
.Wnd
))
3697 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
3701 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
3703 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3704 if (!(Flags
& TPM_NONOTIFY
))
3705 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
3707 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
3708 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
3709 Tpm
? &Tpm
->rcExclude
: NULL
);
3710 MenuExitTracking(Wnd
, TRUE
);
3714 /**********************************************************************
3715 * TrackPopupMenu (USER32.@)
3717 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
3718 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
3720 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
3725 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3726 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3728 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3730 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3731 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3732 * MFT_STRING is replaced by MIIM_STRING.
3733 * (So, I guess we should use MIIM_STRING only for strings?)
3735 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3737 * Based on wine, SetMenuItemInfo_common:
3738 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3739 * it will result in a error.
3740 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3741 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3748 LPMENUITEMINFOW mii
,
3755 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3757 if(Flags
& MF_BITMAP
)
3759 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3760 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3762 if (Flags
& MF_HELP
)
3764 /* increase ident */
3765 mii
->fType
|= MF_HELP
;
3768 else if(Flags
& MF_OWNERDRAW
)
3770 mii
->fType
|= MFT_OWNERDRAW
;
3771 mii
->fMask
|= MIIM_DATA
;
3772 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
3774 else if (Flags
& MF_SEPARATOR
)
3776 mii
->fType
|= MFT_SEPARATOR
;
3777 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3778 Flags
|= MF_GRAYED
|MF_DISABLED
;
3780 else /* Default action MF_STRING. */
3782 /* Item beginning with a backspace is a help item */
3783 if (NewItem
!= NULL
)
3787 if (*NewItem
== '\b')
3789 mii
->fType
|= MF_HELP
;
3795 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3796 if (*NewItemA
== '\b')
3798 mii
->fType
|= MF_HELP
;
3800 NewItem
= (LPCWSTR
) NewItemA
;
3804 if (Flags
& MF_HELP
)
3805 mii
->fType
|= MF_HELP
;
3806 mii
->fMask
|= MIIM_STRING
;
3807 mii
->fType
|= MFT_STRING
; /* Zero */
3808 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3810 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3812 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3816 mii
->fType
|= MFT_SEPARATOR
;
3817 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3818 Flags
|= MF_GRAYED
|MF_DISABLED
;
3822 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3824 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3827 if(Flags
& MF_MENUBREAK
)
3829 mii
->fType
|= MFT_MENUBREAK
;
3831 else if(Flags
& MF_MENUBARBREAK
)
3833 mii
->fType
|= MFT_MENUBARBREAK
;
3836 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3838 if (Flags
& MF_GRAYED
)
3839 mii
->fState
|= MF_GRAYED
;
3841 if (Flags
& MF_DISABLED
)
3842 mii
->fState
|= MF_DISABLED
;
3844 mii
->fMask
|= MIIM_STATE
;
3846 else if (Flags
& MF_HILITE
)
3848 mii
->fState
|= MF_HILITE
;
3849 mii
->fMask
|= MIIM_STATE
;
3851 else /* default state */
3853 mii
->fState
|= MFS_ENABLED
;
3854 mii
->fMask
|= MIIM_STATE
;
3857 if(Flags
& MF_POPUP
)
3859 mii
->fType
|= MF_POPUP
;
3860 mii
->fMask
|= MIIM_SUBMENU
;
3861 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3865 mii
->fMask
|= MIIM_ID
;
3866 mii
->wID
= (UINT
)IDNewItem
;
3872 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3874 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3877 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3879 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3880 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3881 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3882 (LPCWSTR
)&Common
->MenuName
);
3884 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3888 /* FUNCTIONS *****************************************************************/
3891 MenuIsStringItem(ULONG TypeData)
3893 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3901 AppendMenuA(HMENU hMenu
,
3903 UINT_PTR uIDNewItem
,
3906 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3915 AppendMenuW(HMENU hMenu
,
3917 UINT_PTR uIDNewItem
,
3920 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3929 CheckMenuItem(HMENU hmenu
,
3933 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3938 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3941 PROSMENUITEMINFO Items
= NULL
;
3942 UINT cChecked
, cUnchecked
;
3946 if(idFirst
> idLast
)
3949 ItemCount
= GetMenuItemCount(hMenu
);
3951 //mi.cbSize = sizeof(ROSMENUINFO);
3952 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3955 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3957 ERR("MenuGetAllRosMenuItemInfo failed\n");
3961 cChecked
= cUnchecked
= 0;
3963 for (i
= 0 ; i
< ItemCount
; i
++)
3966 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3967 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3969 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3971 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3974 if (uFlags
& MF_BYPOSITION
)
3976 if (i
< idFirst
|| i
> idLast
)
3991 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3994 if (Items
[i
].wID
== idCheck
)
4008 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4011 Items
[i
].fType
|= MFT_RADIOCHECK
;
4012 Items
[i
].fState
|= MFS_CHECKED
;
4016 Items
[i
].fState
&= ~MFS_CHECKED
;
4019 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4021 ERR("MenuSetRosMenuItemInfo failed\n");
4026 HeapFree(GetProcessHeap(), 0, Items
);
4028 *pChecked
+= cChecked
;
4029 *pUnchecked
+= cUnchecked
;
4031 if (cChecked
|| cUnchecked
)
4041 CheckMenuRadioItem(HMENU hmenu
,
4048 UINT cUnchecked
= 0;
4049 UINT cMenuChanged
= 0;
4051 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4054 if (cMenuChanged
> 1)
4061 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4064 return (cChecked
!= 0);
4075 return NtUserxCreateMenu();
4083 CreatePopupMenu(VOID
)
4086 return NtUserxCreatePopupMenu();
4094 DrawMenuBar(HWND hWnd
)
4096 // return NtUserxDrawMenuBar(hWnd);
4097 ROSMENUINFO MenuInfo
;
4099 hMenu
= GetMenu(hWnd
);
4102 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4103 MenuInfo
.Height
= 0; // make sure to recalc size
4104 MenuSetRosMenuInfo(&MenuInfo
);
4106 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4107 SWP_NOZORDER
| SWP_FRAMECHANGED
);
4115 EnableMenuItem(HMENU hMenu
,
4119 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4129 guii
.cbSize
= sizeof(GUITHREADINFO
);
4130 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4134 guii
.hwndMenuOwner
!= top_popup
)
4136 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4140 /* if we are in the menu code, and it is active */
4141 if (!fEndMenu
&& top_popup
)
4143 /* terminate the menu handling code */
4146 /* needs to be posted to wakeup the internal menu handler */
4147 /* which will now terminate the menu, in the event that */
4148 /* the main window was minimized, or lost focus, so we */
4149 /* don't end up with an orphaned menu */
4150 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4155 // So this one maybe one day it will be a callback!
4156 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4159 ROSMENUINFO MenuInfo
;
4160 ROSMENUITEMINFO mii
;
4161 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4164 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4167 if (!NtUserMenuItemInfo(hMenu
, wItemID
, wHilite
, &mii
, FALSE
)) return FALSE
;
4168 if (!NtUserMenuInfo(hMenu
, &MenuInfo
, FALSE
)) return FALSE
;
4169 if (MenuInfo
.FocusedItem
== wItemID
) return TRUE
;
4170 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4171 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4181 PWND Wnd
= ValidateHwnd(hWnd
);
4186 return UlongToHandle(Wnd
->IDMenu
);
4194 GetMenuCheckMarkDimensions(VOID
)
4196 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4197 GetSystemMetrics(SM_CYMENUCHECK
)));
4205 GetMenuDefaultItem(HMENU hMenu
,
4209 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4217 GetMenuInfo(HMENU hmenu
,
4223 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4226 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4227 mi
.cbSize
= sizeof(MENUINFO
);
4228 mi
.fMask
= lpcmi
->fMask
;
4230 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4232 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4241 GetMenuItemCount(HMENU Menu
)
4243 ROSMENUINFO MenuInfo
;
4245 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4253 GetMenuItemID(HMENU hMenu
,
4256 ROSMENUITEMINFO mii
;
4258 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4259 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4261 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4266 if (NULL
!= mii
.hSubMenu
)
4287 LPMENUITEMINFOA mii
)
4293 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4294 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4296 SetLastError(ERROR_INVALID_PARAMETER
);
4300 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4302 /* No text requested, just pass on */
4303 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4306 AnsiBuffer
= mii
->dwTypeData
;
4307 Count
= miiW
.cch
= mii
->cch
;
4308 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4309 miiW
.dwTypeData
= 0;
4313 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4314 miiW
.cch
* sizeof(WCHAR
));
4315 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4316 miiW
.dwTypeData
[0] = 0;
4319 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4321 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4325 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4327 if (!AnsiBuffer
|| !Count
)
4329 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4330 mii
->dwTypeData
= AnsiBuffer
;
4331 mii
->cch
= miiW
.cch
;
4335 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4339 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4343 if (Count
> miiW
.cch
)
4345 AnsiBuffer
[miiW
.cch
] = 0;
4347 mii
->cch
= mii
->cch
;
4355 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4356 mii
->dwTypeData
= AnsiBuffer
;
4370 LPMENUITEMINFOW mii
)
4376 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4377 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4379 SetLastError(ERROR_INVALID_PARAMETER
);
4383 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4385 /* No text requested, just pass on */
4386 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4389 String
= mii
->dwTypeData
;
4391 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4392 miiW
.dwTypeData
= 0;
4396 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4397 miiW
.cch
* sizeof(WCHAR
));
4398 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4399 miiW
.dwTypeData
[0] = 0;
4402 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4404 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4408 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4410 if (!String
|| !Count
)
4412 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4413 mii
->dwTypeData
= String
; // may not be zero.
4414 mii
->cch
= miiW
.cch
;
4418 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4420 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4423 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4424 mii
->dwTypeData
= String
;
4425 mii
->cch
= strlenW(String
);
4440 ROSMENUINFO MenuInfo
;
4441 ROSMENUITEMINFO mii
;
4442 memset( &mii
, 0, sizeof(mii
) );
4443 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4444 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4447 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4452 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4456 nSubItems
= MenuInfo
.MenuItemCount
;
4458 /* FIXME - ported from wine, does that work (0xff)? */
4459 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4460 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4462 return (UINT
)-1; /* Invalid submenu */
4465 /* FIXME - ported from wine, does that work? */
4466 return (mii
.fType
| mii
.fState
);
4486 memset( &mii
, 0, sizeof(mii
) );
4487 mii
.dwTypeData
= lpString
;
4488 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4489 mii
.fType
= MFT_STRING
;
4490 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4491 mii
.cch
= nMaxCount
;
4493 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4513 memset( &miiW
, 0, sizeof(miiW
) );
4514 miiW
.dwTypeData
= lpString
;
4515 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4516 miiW
.fType
= MFT_STRING
;
4517 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4518 miiW
.cch
= nMaxCount
;
4520 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4538 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4539 mi
.fMask
= MIIM_SUBMENU
;
4541 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4543 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4560 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4562 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4575 UINT_PTR uIDNewItem
,
4579 memset( &mii
, 0, sizeof(mii
) );
4580 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4581 mii
.fMask
= MIIM_FTYPE
;
4583 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4586 (LPCWSTR
) lpNewItem
,
4589 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4603 LPCMENUITEMINFOA lpmii
)
4606 UNICODE_STRING MenuText
;
4608 BOOL CleanHeap
= FALSE
;
4611 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4612 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4614 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4616 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4618 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4621 /* copy the text string */
4622 if (((mi
.fMask
& MIIM_STRING
) ||
4623 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4624 && mi
.dwTypeData
!= NULL
)
4626 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4627 if (!NT_SUCCESS (Status
))
4629 SetLastError (RtlNtStatusToDosError(Status
));
4632 mi
.dwTypeData
= MenuText
.Buffer
;
4633 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4636 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4638 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4653 LPCMENUITEMINFOW lpmii
)
4656 UNICODE_STRING MenuText
;
4659 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4660 if a bad user passes bad data, we crash his process instead of the
4663 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4664 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4666 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4668 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4670 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4673 /* copy the text string */
4674 if (((mi
.fMask
& MIIM_STRING
) ||
4675 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4676 && mi
.dwTypeData
!= NULL
)
4678 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4679 mi
.dwTypeData
= MenuText
.Buffer
;
4680 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4682 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4697 UINT_PTR uIDNewItem
,
4701 memset( &mii
, 0, sizeof(mii
) );
4702 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4703 mii
.fMask
= MIIM_FTYPE
;
4705 MenuSetItemData( &mii
,
4711 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4723 if (ValidateHandle(Menu
, otMenu
)) return TRUE
;
4732 LoadMenuA(HINSTANCE hInstance
,
4735 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4736 if (Resource
== NULL
)
4740 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4748 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4750 return(LoadMenuIndirectW(lpMenuTemplate
));
4758 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4761 WORD version
, offset
;
4762 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4764 version
= GET_WORD(p
);
4769 case 0: /* standard format is version of 0 */
4770 offset
= GET_WORD(p
);
4771 p
+= sizeof(WORD
) + offset
;
4772 if (!(hMenu
= CreateMenu())) return 0;
4773 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4779 case 1: /* extended format is version of 1 */
4780 offset
= GET_WORD(p
);
4781 p
+= sizeof(WORD
) + offset
;
4782 if (!(hMenu
= CreateMenu())) return 0;
4783 if (!MENUEX_ParseResource(p
, hMenu
))
4785 DestroyMenu( hMenu
);
4790 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4800 LoadMenuW(HINSTANCE hInstance
,
4803 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4804 if (Resource
== NULL
)
4808 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4822 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4835 UINT_PTR uIDNewItem
,
4839 ROSMENUITEMINFO rmii
;
4841 memset( &mii
, 0, sizeof(mii
) );
4842 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4843 mii
.fMask
= MIIM_FTYPE
;
4845 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4849 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4851 MenuInitRosMenuItemInfo( &rmii
);
4853 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4855 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4856 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4858 MenuCleanupRosMenuItemInfo( &rmii
);
4860 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4863 (LPCWSTR
) lpNewItem
,
4866 return SetMenuItemInfoA( hMnu
,
4868 (BOOL
)(MF_BYPOSITION
& uFlags
),
4882 UINT_PTR uIDNewItem
,
4886 ROSMENUITEMINFO rmii
;
4888 memset ( &mii
, 0, sizeof(mii
) );
4889 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4890 mii
.fMask
= MIIM_FTYPE
;
4892 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4894 mi
.Height
= 0; // Force size recalculation.
4896 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4898 MenuInitRosMenuItemInfo( &rmii
);
4900 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4902 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4903 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4905 MenuCleanupRosMenuItemInfo( &rmii
);
4907 /* Init new data for this menu item */
4908 MenuSetItemData( &mii
,
4914 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4915 return SetMenuItemInfoW( hMnu
,
4917 (BOOL
)(MF_BYPOSITION
& uFlags
),
4929 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4945 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4947 SetLastError(ERROR_INVALID_PARAMETER
);
4951 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4952 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4965 HBITMAP hBitmapUnchecked
,
4966 HBITMAP hBitmapChecked
)
4968 ROSMENUITEMINFO uItem
;
4969 memset ( &uItem
, 0, sizeof(uItem
) );
4970 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4972 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4973 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4975 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4977 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4979 else /* Install new bitmaps */
4981 uItem
.hbmpChecked
= hBitmapChecked
;
4982 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4983 uItem
.fState
|= MF_USECHECKBITMAPS
;
4985 return NtUserMenuItemInfo(hMenu
, uPosition
,
4986 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4999 LPCMENUITEMINFOA lpmii
)
5001 MENUITEMINFOW MenuItemInfoW
;
5002 UNICODE_STRING UnicodeString
;
5004 ULONG Result
= FALSE
;
5006 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5008 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5010 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5011 MenuItemInfoW
.hbmpItem
= NULL
;
5014 * MIIM_STRING == good
5015 * MIIM_TYPE & MFT_STRING == good
5016 * MIIM_STRING & MFT_STRING == good
5017 * MIIM_STRING & MFT_OWNERSRAW == good
5019 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5020 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5021 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5022 && MenuItemInfoW
.dwTypeData
!= NULL
)
5024 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5025 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5026 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5027 if (!NT_SUCCESS (Status
))
5029 SetLastError (RtlNtStatusToDosError(Status
));
5032 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5033 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5037 UnicodeString
.Buffer
= NULL
;
5040 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5041 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5043 if (UnicodeString
.Buffer
!= NULL
)
5045 RtlFreeUnicodeString(&UnicodeString
);
5061 LPCMENUITEMINFOW lpmii
)
5063 MENUITEMINFOW MenuItemInfoW
;
5066 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5068 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5070 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5071 MenuItemInfoW
.hbmpItem
= NULL
;
5074 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5075 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5076 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5077 && MenuItemInfoW
.dwTypeData
!= NULL
)
5079 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5081 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5082 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5098 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5103 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5106 return NtUserSetSystemMenu(hwnd
, hMenu
);
5110 // Example for the Win32/User32 rewrite.
5111 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5125 return NtUserTrackPopupMenuEx( Menu
,
5130 NULL
); // LPTPMPARAMS is null
5139 GetMenuContextHelpId(HMENU hmenu
)
5142 mi
.cbSize
= sizeof(ROSMENUINFO
);
5143 mi
.fMask
= MIM_HELPID
;
5145 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5147 return mi
.dwContextHelpID
;
5168 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5171 Result
= (ULONG_PTR
)lResult
;
5176 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5196 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5199 Result
= (ULONG_PTR
)lResult
;
5204 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5215 LPCWSTR lpszNewItem
,
5220 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5221 for MF_DELETE. We should check the parameters for all others
5222 MF_* actions also (anybody got a doc on ChangeMenu?).
5225 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5228 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5231 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5234 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5237 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5238 flags
&~ MF_REMOVE
);
5240 default : /* MF_INSERT */
5241 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5258 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5259 for MF_DELETE. We should check the parameters for all others
5260 MF_* actions also (anybody got a doc on ChangeMenu?).
5263 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5266 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5269 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5272 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5275 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5276 flags
&~ MF_REMOVE
);
5278 default : /* MF_INSERT */
5279 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);