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)
69 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
70 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
71 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
72 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
77 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
78 HMENU TopMenu
; /* initial menu */
79 HWND OwnerWnd
; /* where notifications are sent */
84 /*********************************************************************
85 * PopupMenu class descriptor
87 const struct builtin_class_descr POPUPMENU_builtin_class
=
89 POPUPMENU_CLASS_ATOMW
, /* name */
90 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
91 (WNDPROC
) NULL
, /* FIXME - procA */
92 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
93 sizeof(MENUINFO
*), /* extra */
94 (LPCWSTR
) IDC_ARROW
, /* cursor */
95 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
99 #define GET_WORD(ptr) (*(WORD *)(ptr))
102 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
105 HFONT hMenuFont
= NULL
;
106 HFONT hMenuFontBold
= NULL
;
108 /* Dimension of the menu bitmaps */
109 static HBITMAP BmpSysMenu
= NULL
;
111 static SIZE MenuCharSize
;
113 /***********************************************************************
116 * Get full information about menu
119 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
121 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
122 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
124 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
127 /***********************************************************************
130 * Set full information about menu
133 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
135 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
136 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
138 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
141 /***********************************************************************
142 * MenuInitRosMenuItemInfo
144 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
147 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
149 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
150 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
153 /***********************************************************************
154 * MenuGetRosMenuItemInfo
156 * Get full information about a menu item
159 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
161 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
163 if (ItemInfo
->dwTypeData
!= NULL
)
165 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
169 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
170 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
171 ItemInfo
->dwTypeData
= NULL
;
173 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
179 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
182 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
183 ItemInfo
->cch
* sizeof(WCHAR
));
184 if (NULL
== ItemInfo
->dwTypeData
)
189 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
194 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
196 ItemInfo
->fMask
= Save_Mask
;
200 /***********************************************************************
201 * MenuSetRosMenuItemInfo
203 * Set selected information about a menu item, need to set the mask bits.
206 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
210 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
211 ItemInfo
->dwTypeData
!= NULL
)
213 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
215 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
220 /***********************************************************************
221 * MenuCleanupRosMenuItemInfo
223 * Cleanup after use of MenuGet/SetRosMenuItemInfo
226 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
228 if (ItemInfo
->dwTypeData
!= NULL
)
230 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
231 ItemInfo
->dwTypeData
= NULL
;
235 /***********************************************************************
236 * MenuGetAllRosMenuItemInfo
238 * Get full information about all menu items
241 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
245 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
246 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
250 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
251 if (NULL
== *ItemInfo
)
256 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
259 /***********************************************************************
260 * MenuCleanupAllRosMenuItemInfo
262 * Cleanup after use of MenuGetAllRosMenuItemInfo
265 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
267 HeapFree(GetProcessHeap(), 0, ItemInfo
);
270 /***********************************************************************
271 * MenuInitSysMenuPopup
273 * Grey the appropriate items in System menu.
275 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
283 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
284 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
285 gray
= ((style
& WS_MAXIMIZE
) != 0);
286 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
287 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
288 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
289 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
290 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
291 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
292 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
293 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
295 /* The menu item must keep its state if it's disabled */
297 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
299 /* Set default menu item */
300 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
301 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
302 else DefItem
= SC_CLOSE
;
304 mii
.cbSize
= sizeof(MENUITEMINFOW
);
305 mii
.fMask
|= MIIM_STATE
;
306 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
307 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
309 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
312 /******************************************************************************
314 * UINT MenuGetStartOfNextColumn(
315 * PROSMENUINFO MenuInfo)
317 *****************************************************************************/
318 static UINT
MenuGetStartOfNextColumn(
319 PROSMENUINFO MenuInfo
)
321 PROSMENUITEMINFO MenuItems
;
324 i
= MenuInfo
->FocusedItem
;
325 if ( i
== NO_SELECTED_ITEM
)
328 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
329 return NO_SELECTED_ITEM
;
331 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
332 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
335 return NO_SELECTED_ITEM
;
338 /******************************************************************************
340 * UINT MenuGetStartOfPrevColumn(
341 * PROSMENUINFO MenuInfo)
343 *****************************************************************************/
345 static UINT FASTCALL
MenuGetStartOfPrevColumn(
346 PROSMENUINFO MenuInfo
)
348 PROSMENUITEMINFO MenuItems
;
351 if (!MenuInfo
->FocusedItem
|| MenuInfo
->FocusedItem
== NO_SELECTED_ITEM
)
352 return NO_SELECTED_ITEM
;
354 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
355 return NO_SELECTED_ITEM
;
357 /* Find the start of the column */
358 for (i
= MenuInfo
->FocusedItem
;
359 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
367 MenuCleanupAllRosMenuItemInfo(MenuItems
);
368 return NO_SELECTED_ITEM
;
371 for (--i
; 0 != i
; --i
)
372 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
375 MenuCleanupAllRosMenuItemInfo(MenuItems
);
376 TRACE("ret %d.\n", i
);
381 /***********************************************************************
384 * Find a Sub menu. Return the position of the submenu, and modifies
385 * *hmenu in case it is found in another sub-menu.
386 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
388 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
392 ROSMENUITEMINFO item
;
393 if (((*hmenu
)==(HMENU
)0xffff) ||
394 (!MenuGetRosMenuInfo(&menu
, *hmenu
)))
395 return NO_SELECTED_ITEM
;
397 MenuInitRosMenuItemInfo(&item
);
398 for (i
= 0; i
< menu
.MenuItemCount
; i
++) {
399 if (! MenuGetRosMenuItemInfo(menu
.Self
, i
, &item
))
401 MenuCleanupRosMenuItemInfo(&item
);
402 return NO_SELECTED_ITEM
;
404 if (!(item
.fType
& MF_POPUP
)) continue;
405 if (item
.hSubMenu
== hSubTarget
) {
406 MenuCleanupRosMenuItemInfo(&item
);
410 HMENU hsubmenu
= item
.hSubMenu
;
411 UINT pos
= MenuFindSubMenu(&hsubmenu
, hSubTarget
);
412 if (pos
!= NO_SELECTED_ITEM
) {
418 MenuCleanupRosMenuItemInfo(&item
);
419 return NO_SELECTED_ITEM
;
422 /***********************************************************************
425 * Load the arrow bitmap. We can't do this from MenuInit since user32
426 * can also be used (and thus initialized) from text-mode.
429 MenuLoadBitmaps(VOID
)
431 /* Load system buttons bitmaps */
432 if (NULL
== BmpSysMenu
)
434 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
438 /***********************************************************************
441 * Draws popup magic glyphs (can be found in system menu).
444 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
447 HFONT hFont
, hOldFont
;
453 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
456 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
459 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
462 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
466 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
469 ZeroMemory(&lf
, sizeof(LOGFONTW
));
470 InflateRect(r
, -2, -2);
471 lf
.lfHeight
= r
->bottom
- r
->top
;
473 lf
.lfWeight
= FW_NORMAL
;
474 lf
.lfCharSet
= DEFAULT_CHARSET
;
475 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
476 hFont
= CreateFontIndirect(&lf
);
477 /* save font and text color */
478 hOldFont
= SelectObject(dc
, hFont
);
479 clrsave
= GetTextColor(dc
);
480 bkmode
= GetBkMode(dc
);
481 /* set color and drawing mode */
482 SetBkMode(dc
, TRANSPARENT
);
488 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
489 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
492 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
493 /* draw selected symbol */
494 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
495 /* restore previous settings */
496 SetTextColor(dc
, clrsave
);
497 SelectObject(dc
, hOldFont
);
498 SetBkMode(dc
, bkmode
);
502 /***********************************************************************
505 * Find the menu item selected by a key press.
506 * Return item id, -1 if none, -2 if we should close the menu.
508 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
509 WCHAR Key
, BOOL ForceMenuChar
)
511 ROSMENUINFO SysMenuInfo
;
512 PROSMENUITEMINFO Items
, ItemInfo
;
516 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
518 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
520 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
522 MenuInfo
= &SysMenuInfo
;
530 if (NULL
!= MenuInfo
)
532 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
540 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
542 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
544 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
547 p
= strchrW(p
+ 2, '&');
549 while (NULL
!= p
&& L
'&' == p
[1]);
550 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
558 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
559 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
560 if (2 == HIWORD(MenuChar
))
562 return LOWORD(MenuChar
);
564 if (1 == HIWORD(MenuChar
))
573 /***********************************************************************
574 * MenuGetBitmapItemSize
576 * Get the size of a bitmap item.
578 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
581 HBITMAP bmp
= lpitem
->hbmpItem
;
583 size
->cx
= size
->cy
= 0;
585 /* check if there is a magic menu item associated with this item */
586 if (IS_MAGIC_BITMAP(bmp
))
588 switch((INT_PTR
) bmp
)
590 case (INT_PTR
)HBMMENU_CALLBACK
:
592 MEASUREITEMSTRUCT measItem
;
593 measItem
.CtlType
= ODT_MENU
;
595 measItem
.itemID
= lpitem
->wID
;
596 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
597 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
598 measItem
.itemData
= lpitem
->dwItemData
;
599 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
600 size
->cx
= measItem
.itemWidth
;
601 size
->cy
= measItem
.itemHeight
;
606 case (INT_PTR
) HBMMENU_SYSTEM
:
607 if (0 != lpitem
->dwItemData
)
609 bmp
= (HBITMAP
) lpitem
->dwItemData
;
613 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
614 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
615 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
616 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
617 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
618 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
619 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
620 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
621 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
622 /* FIXME: Why we need to subtract these magic values? */
623 /* to make them smaller than the menu bar? */
624 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
625 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
630 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
632 size
->cx
= bm
.bmWidth
;
633 size
->cy
= bm
.bmHeight
;
637 /***********************************************************************
640 * Draw a bitmap item.
642 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
643 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
649 int w
= rect
->right
- rect
->left
;
650 int h
= rect
->bottom
- rect
->top
;
653 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
656 /* Check if there is a magic menu item associated with this item */
657 if (IS_MAGIC_BITMAP(hbmToDraw
))
663 switch ((INT_PTR
)hbmToDraw
)
665 case (INT_PTR
)HBMMENU_SYSTEM
:
666 if (lpitem
->dwTypeData
)
668 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
669 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
673 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
675 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
676 /* only use right half of the bitmap */
677 bmp_xoffset
= bm
.bmWidth
/ 2;
678 bm
.bmWidth
-= bmp_xoffset
;
681 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
682 flags
= DFCS_CAPTIONRESTORE
;
684 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
686 flags
= DFCS_CAPTIONMIN
;
688 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
690 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
692 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
693 flags
= DFCS_CAPTIONCLOSE
;
695 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
696 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
698 case (INT_PTR
)HBMMENU_CALLBACK
:
700 DRAWITEMSTRUCT drawItem
;
702 drawItem
.CtlType
= ODT_MENU
;
704 drawItem
.itemID
= lpitem
->wID
;
705 drawItem
.itemAction
= odaction
;
706 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
707 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
708 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
709 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
710 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
711 drawItem
.hwndItem
= (HWND
)hmenu
;
713 drawItem
.rcItem
= *rect
;
714 drawItem
.itemData
= lpitem
->dwItemData
;
715 /* some applications make this assumption on the DC's origin */
716 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
717 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
718 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
719 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
724 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
725 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
726 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
727 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
728 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
731 InflateRect(&r
, -1, -1);
732 if (0 != (lpitem
->fState
& MF_HILITE
))
734 flags
|= DFCS_PUSHED
;
736 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
740 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
743 hdcMem
= CreateCompatibleDC( hdc
);
744 SelectObject( hdcMem
, bmp
);
746 /* handle fontsize > bitmap_height */
747 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
749 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
750 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
751 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
752 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
756 /***********************************************************************
759 * Calculate the size of the menu item and store it in lpitem->rect.
761 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
762 INT orgX
, INT orgY
, BOOL menuBar
)
765 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
768 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
770 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
772 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
774 if (lpitem
->fType
& MF_OWNERDRAW
)
776 MEASUREITEMSTRUCT mis
;
777 mis
.CtlType
= ODT_MENU
;
779 mis
.itemID
= lpitem
->wID
;
780 mis
.itemData
= lpitem
->dwItemData
;
781 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
783 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
784 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
785 * width of a menufont character to the width of an owner-drawn menu.
787 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
790 /* under at least win95 you seem to be given a standard
791 height for the menu and the height value is ignored */
792 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
794 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
796 TRACE("id=%04lx size=%dx%d\n",
797 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
801 if (lpitem
->fType
& MF_SEPARATOR
)
803 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
805 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
811 if (lpitem
->hbmpItem
)
816 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
817 /* Keep the size of the bitmap in callback mode to be able
818 * to draw it correctly */
819 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
820 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
821 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
823 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
824 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
826 MenuSetRosMenuInfo(MenuInfo
);
827 itemheight
= size
.cy
+ 2;
829 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
830 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
831 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
832 lpitem
->dxTab
= lpitem
->Rect
.right
;
833 lpitem
->Rect
.right
+= check_bitmap_width
;
834 } else /* hbmpItem & MenuBar */ {
835 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
836 lpitem
->Rect
.right
+= size
.cx
;
837 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
838 itemheight
= size
.cy
;
840 /* Special case: Minimize button doesn't have a space behind it. */
841 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
842 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
843 lpitem
->Rect
.right
-= 1;
847 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
848 lpitem
->Rect
.right
+= check_bitmap_width
;
849 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
850 lpitem
->dxTab
= lpitem
->Rect
.right
;
851 lpitem
->Rect
.right
+= check_bitmap_width
;
854 /* it must be a text item - unless it's the system menu */
855 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
856 HFONT hfontOld
= NULL
;
857 RECT rc
= lpitem
->Rect
;
858 LONG txtheight
, txtwidth
;
860 if ( lpitem
->fState
& MFS_DEFAULT
) {
861 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
864 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
865 DT_SINGLELINE
|DT_CALCRECT
);
866 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
867 itemheight
= max( max( itemheight
, txtheight
),
868 GetSystemMetrics( SM_CYMENU
) - 1);
869 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
871 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
874 int n
= (int)( p
- lpitem
->dwTypeData
);
875 /* Item contains a tab (only meaningful in popup menus) */
876 /* get text size before the tab */
877 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
878 DT_SINGLELINE
|DT_CALCRECT
);
879 txtwidth
= rc
.right
- rc
.left
;
880 p
+= 1; /* advance past the Tab */
881 /* get text size after the tab */
882 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
883 DT_SINGLELINE
|DT_CALCRECT
);
884 lpitem
->dxTab
+= txtwidth
;
885 txtheight
= max( txtheight
, tmpheight
);
886 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
887 tmprc
.right
- tmprc
.left
; /* space for the short cut */
889 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
890 DT_SINGLELINE
|DT_CALCRECT
);
891 txtwidth
= rc
.right
- rc
.left
;
892 lpitem
->dxTab
+= txtwidth
;
894 lpitem
->Rect
.right
+= 2 + txtwidth
;
895 itemheight
= max( itemheight
,
896 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
898 if (hfontOld
) SelectObject (hdc
, hfontOld
);
899 } else if( menuBar
) {
900 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
902 lpitem
->Rect
.bottom
+= itemheight
;
903 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
906 /***********************************************************************
907 * MenuPopupMenuCalcSize
909 * Calculate the size of a popup menu.
911 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
913 ROSMENUITEMINFO lpitem
;
916 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
918 MenuInfo
->Width
= MenuInfo
->Height
= 0;
919 if (MenuInfo
->MenuItemCount
== 0)
921 MenuSetRosMenuInfo(MenuInfo
);
926 SelectObject( hdc
, hMenuFont
);
931 MenuInfo
->maxBmpSize
.cx
= 0;
932 MenuInfo
->maxBmpSize
.cy
= 0;
934 MenuInitRosMenuItemInfo(&lpitem
);
935 while (start
< MenuInfo
->MenuItemCount
)
940 maxTab
= maxTabWidth
= 0;
942 /* Parse items until column break or end of menu */
943 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
945 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
947 MenuCleanupRosMenuItemInfo(&lpitem
);
948 MenuSetRosMenuInfo(MenuInfo
);
952 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
954 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
955 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
957 MenuCleanupRosMenuItemInfo(&lpitem
);
958 MenuSetRosMenuInfo(MenuInfo
);
961 // Not sure here,, The patch from wine removes this.
962 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
966 maxX
= max(maxX
, lpitem
.Rect
.right
);
967 orgY
= lpitem
.Rect
.bottom
;
968 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
970 maxTab
= max( maxTab
, lpitem
.dxTab
);
971 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
975 /* Finish the column (set all items to the largest width found) */
976 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
979 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
981 lpitem
.Rect
.right
= maxX
;
982 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
984 lpitem
.dxTab
= maxTab
;
986 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
990 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
993 MenuInfo
->Width
= maxX
;
995 /* space for 3d border */
996 MenuInfo
->Height
+= 2;
997 MenuInfo
->Width
+= 2;
999 MenuCleanupRosMenuItemInfo(&lpitem
);
1000 MenuSetRosMenuInfo(MenuInfo
);
1001 ReleaseDC( 0, hdc
);
1004 /***********************************************************************
1005 * MenuMenuBarCalcSize
1007 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1008 * height is off by 1 pixel which causes lengthy window relocations when
1009 * active document window is maximized/restored.
1011 * Calculate the size of the menu bar.
1013 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1014 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1016 ROSMENUITEMINFO ItemInfo
;
1017 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1019 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1020 if (MenuInfo
->MenuItemCount
== 0) return;
1021 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1022 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1023 MenuInfo
->Height
= 0;
1024 maxY
= lprect
->top
+ 1;
1028 MenuInfo
->maxBmpSize
.cx
= 0;
1029 MenuInfo
->maxBmpSize
.cy
= 0;
1031 MenuInitRosMenuItemInfo(&ItemInfo
);
1032 while (start
< MenuInfo
->MenuItemCount
)
1034 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1036 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1039 orgX
= lprect
->left
;
1042 /* Parse items until line break or end of menu */
1043 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1045 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1047 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1049 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1050 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1051 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1053 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1057 if (ItemInfo
.Rect
.right
> lprect
->right
)
1059 if (i
!= start
) break;
1060 else ItemInfo
.Rect
.right
= lprect
->right
;
1062 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1063 orgX
= ItemInfo
.Rect
.right
;
1064 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1066 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1068 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1074 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1075 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1077 /* Finish the line (set all items to the largest height found) */
1080 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1082 ItemInfo
.Rect
.bottom
= maxY
;
1083 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1088 start
= i
; /* This works! */
1092 lprect
->bottom
= maxY
;
1093 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1094 MenuSetRosMenuInfo(MenuInfo
);
1098 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1099 /* the last item (if several lines, only move the last line) */
1100 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1102 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1105 orgY
= ItemInfo
.Rect
.top
;
1106 orgX
= lprect
->right
;
1107 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1113 if (ItemInfo
.Rect
.top
!= orgY
)
1115 break; /* Other line */
1117 if (orgX
<= ItemInfo
.Rect
.right
)
1119 break; /* Too far right already */
1121 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1122 ItemInfo
.Rect
.right
= orgX
;
1123 orgX
= ItemInfo
.Rect
.left
;
1124 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1125 if (helpPos
+ 1 <= i
&&
1126 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1128 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1134 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1137 /***********************************************************************
1140 * Draw a single menu item.
1142 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1143 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1147 BOOL flat_menu
= FALSE
;
1149 PWND Wnd
= ValidateHwnd(hWnd
);
1154 if (lpitem
->fType
& MF_SYSMENU
)
1156 if ( (Wnd
->style
& WS_MINIMIZE
))
1158 UserGetInsideRectNC(Wnd
, &rect
);
1159 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1160 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1165 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1166 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1170 if (lpitem
->fState
& MF_HILITE
)
1172 if(menuBar
&& !flat_menu
) {
1173 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1174 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1176 if (lpitem
->fState
& MF_GRAYED
)
1177 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1179 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1180 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1185 if (lpitem
->fState
& MF_GRAYED
)
1186 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1188 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1189 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1192 rect
= lpitem
->Rect
;
1194 if (lpitem
->fType
& MF_OWNERDRAW
)
1197 ** Experimentation under Windows reveals that an owner-drawn
1198 ** menu is given the rectangle which includes the space it requested
1199 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1200 ** and a popup-menu arrow. This is the value of lpitem->rect.
1201 ** Windows will leave all drawing to the application except for
1202 ** the popup-menu arrow. Windows always draws that itself, after
1203 ** the menu owner has finished drawing.
1207 dis
.CtlType
= ODT_MENU
;
1209 dis
.itemID
= lpitem
->wID
;
1210 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1212 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1213 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1214 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1215 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1216 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1219 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1220 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1221 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1222 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1224 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1225 /* Draw the popup-menu arrow */
1226 if (lpitem
->fType
& MF_POPUP
)
1229 CopyRect(&rectTemp
, &rect
);
1230 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1231 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1236 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1238 if (lpitem
->fState
& MF_HILITE
)
1242 InflateRect (&rect
, -1, -1);
1243 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1244 InflateRect (&rect
, 1, 1);
1245 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1250 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1252 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1256 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1258 SetBkMode( hdc
, TRANSPARENT
);
1260 /* vertical separator */
1261 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1268 rc
.bottom
= Height
- 3;
1271 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1272 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1273 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1274 LineTo( hdc
, rc
.left
, rc
.bottom
);
1275 SelectObject( hdc
, oldPen
);
1278 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1281 /* horizontal separator */
1282 if (lpitem
->fType
& MF_SEPARATOR
)
1289 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1292 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1293 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1294 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1295 LineTo( hdc
, rc
.right
, rc
.top
);
1296 SelectObject( hdc
, oldPen
);
1299 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1304 /* helper lines for debugging */
1305 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1306 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1307 SelectObject(hdc
, GetStockObject(DC_PEN
));
1308 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1309 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1310 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1316 INT y
= rect
.top
+ rect
.bottom
;
1318 int checked
= FALSE
;
1319 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1320 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1321 /* Draw the check mark
1324 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1326 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1327 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1328 lpitem
->hbmpUnchecked
;
1329 if (bm
) /* we have a custom bitmap */
1331 HDC hdcMem
= CreateCompatibleDC( hdc
);
1333 SelectObject( hdcMem
, bm
);
1334 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1335 check_bitmap_width
, check_bitmap_height
,
1336 hdcMem
, 0, 0, SRCCOPY
);
1340 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1343 CopyRect(&r
, &rect
);
1344 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1345 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1346 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1347 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1351 if ( lpitem
->hbmpItem
)
1354 CopyRect(&bmpRect
, &rect
);
1355 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1356 bmpRect
.left
+= check_bitmap_width
+ 2;
1357 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1359 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1360 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1363 /* Draw the popup-menu arrow */
1364 if (lpitem
->fType
& MF_POPUP
)
1367 CopyRect(&rectTemp
, &rect
);
1368 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1369 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1372 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1373 rect
.left
+= check_bitmap_width
;
1374 rect
.right
-= check_bitmap_width
;
1376 else if( lpitem
->hbmpItem
)
1377 { /* Draw the bitmap */
1378 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1381 /* process text if present */
1387 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1388 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1390 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1391 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1393 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1395 if ( lpitem
->fState
& MFS_DEFAULT
)
1397 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1401 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1402 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1405 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1408 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1409 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1413 if(lpitem
->fState
& MF_GRAYED
)
1415 if (!(lpitem
->fState
& MF_HILITE
) )
1417 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1418 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1419 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1420 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1422 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1425 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1427 /* paint the shortcut text */
1428 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1430 if (L
'\t' == Text
[i
])
1432 rect
.left
= lpitem
->dxTab
;
1433 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1437 rect
.right
= lpitem
->dxTab
;
1438 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1441 if (lpitem
->fState
& MF_GRAYED
)
1443 if (!(lpitem
->fState
& MF_HILITE
) )
1445 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1446 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1447 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1448 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1450 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1452 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1456 SelectObject (hdc
, hfontOld
);
1460 /***********************************************************************
1463 * Paint a popup menu.
1465 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1467 HBRUSH hPrevBrush
= 0;
1470 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1472 GetClientRect( hwnd
, &rect
);
1474 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1475 && (SelectObject( hdc
, hMenuFont
)))
1479 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1481 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1484 BOOL flat_menu
= FALSE
;
1485 ROSMENUINFO MenuInfo
;
1486 ROSMENUITEMINFO ItemInfo
;
1488 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1490 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1492 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1494 /* draw menu items */
1495 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1499 MenuInitRosMenuItemInfo(&ItemInfo
);
1501 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1503 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1505 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1506 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1510 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1514 SelectObject( hdc
, hPrevBrush
);
1519 /***********************************************************************
1522 * Paint a menu bar. Returns the height of the menu bar.
1523 * called from [windows/nonclient.c]
1525 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1530 HMENU hMenu
= GetMenu(hwnd
);
1532 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1534 return GetSystemMetrics(SM_CYMENU
);
1539 hfontOld
= SelectObject(hDC
, hMenuFont
);
1541 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1543 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1545 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1546 return lppop
.Height
;
1549 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1552 /***********************************************************************
1555 * Display a popup menu.
1557 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1558 INT x
, INT y
, INT xanchor
, INT yanchor
)
1560 ROSMENUINFO MenuInfo
;
1561 ROSMENUITEMINFO ItemInfo
;
1567 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1568 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1570 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1571 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1573 MenuInitRosMenuItemInfo(&ItemInfo
);
1574 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1576 ItemInfo
.fMask
|= MIIM_STATE
;
1577 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1578 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1580 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1581 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1584 /* store the owner for DrawItem */
1585 MenuInfo
.WndOwner
= hwndOwner
;
1586 MenuSetRosMenuInfo(&MenuInfo
);
1588 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1590 /* adjust popup menu pos so that it fits within the desktop */
1592 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1593 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1595 /* FIXME: should use item rect */
1598 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1599 info
.cbSize
= sizeof(info
);
1600 GetMonitorInfoW( monitor
, &info
);
1602 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1603 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1605 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1606 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1608 if( x
+ width
> info
.rcMonitor
.right
)
1610 if( xanchor
&& x
>= width
- xanchor
)
1611 x
-= width
- xanchor
;
1613 if( x
+ width
> info
.rcMonitor
.right
)
1614 x
= info
.rcMonitor
.right
- width
;
1616 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
1618 if( y
+ height
> info
.rcMonitor
.bottom
)
1620 if( yanchor
&& y
>= height
+ yanchor
)
1621 y
-= height
+ yanchor
;
1623 if( y
+ height
> info
.rcMonitor
.bottom
)
1624 y
= info
.rcMonitor
.bottom
- height
;
1626 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
1628 /* NOTE: In Windows, top menu popup is not owned. */
1629 MenuInfo
.Wnd
= CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW
, NULL
,
1630 WS_POPUP
, x
, y
, width
, height
,
1631 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1632 (LPVOID
) MenuInfo
.Self
);
1633 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1635 top_popup
= MenuInfo
.Wnd
;
1636 top_popup_hmenu
= hmenu
;
1639 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1641 /* Display the window */
1643 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1644 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1645 UpdateWindow( MenuInfo
.Wnd
);
1650 /***********************************************************************
1653 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1654 BOOL sendMenuSelect
, HMENU topmenu
)
1656 ROSMENUITEMINFO ItemInfo
;
1657 ROSMENUINFO TopMenuInfo
;
1660 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1662 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1663 if (hmenu
->FocusedItem
== wIndex
) return;
1664 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1665 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1667 top_popup
= hmenu
->Wnd
;
1668 top_popup_hmenu
= hmenu
->Self
;
1671 SelectObject( hdc
, hMenuFont
);
1673 MenuInitRosMenuItemInfo(&ItemInfo
);
1675 /* Clear previous highlighted item */
1676 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1678 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1680 ItemInfo
.fMask
|= MIIM_STATE
;
1681 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1682 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1684 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1685 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1689 /* Highlight new item (if any) */
1690 hmenu
->FocusedItem
= wIndex
;
1691 MenuSetRosMenuInfo(hmenu
);
1692 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1694 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1696 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1698 ItemInfo
.fMask
|= MIIM_STATE
;
1699 ItemInfo
.fState
|= MF_HILITE
;
1700 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1701 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1702 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1707 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1708 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1709 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1710 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1714 else if (sendMenuSelect
) {
1717 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1718 if (pos
!= NO_SELECTED_ITEM
)
1720 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1721 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1723 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1724 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1726 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1732 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1733 ReleaseDC(hmenu
->Wnd
, hdc
);
1736 /***********************************************************************
1739 * Moves currently selected item according to the Offset parameter.
1740 * If there is no selection then it should select the last item if
1741 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1743 static void FASTCALL
1744 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1747 ROSMENUITEMINFO ItemInfo
;
1750 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1752 /* Prevent looping */
1753 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1755 else if (Offset
< -1)
1757 else if (Offset
> 1)
1760 MenuInitRosMenuItemInfo(&ItemInfo
);
1762 OrigPos
= MenuInfo
->FocusedItem
;
1763 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1770 i
= MenuInfo
->FocusedItem
;
1777 /* Clip and wrap around */
1780 i
= MenuInfo
->MenuItemCount
- 1;
1782 else if (i
>= MenuInfo
->MenuItemCount
)
1786 /* If this is a good candidate; */
1787 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1788 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1790 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1791 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1794 } while (i
!= OrigPos
);
1797 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1800 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1802 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1808 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1809 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1813 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1814 return MA_NOACTIVATE
;
1819 BeginPaint(Wnd
, &ps
);
1820 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1825 case WM_PRINTCLIENT
:
1827 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1828 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1836 /* zero out global pointer in case resident popup window was destroyed. */
1837 if (Wnd
== top_popup
)
1840 top_popup_hmenu
= NULL
;
1847 if (0 == GetWindowLongPtrA(Wnd
, 0))
1849 OutputDebugStringA("no menu to display\n");
1854 SetWindowLongPtrA(Wnd
, 0, 0);
1858 case MM_SETMENUHANDLE
:
1859 SetWindowLongPtrA(Wnd
, 0, wParam
);
1862 case MM_GETMENUHANDLE
:
1864 return GetWindowLongPtrA(Wnd
, 0);
1867 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1873 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1875 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1881 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1882 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1886 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1887 return MA_NOACTIVATE
;
1892 BeginPaint(Wnd
, &ps
);
1893 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1898 case WM_PRINTCLIENT
:
1900 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1901 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1909 /* zero out global pointer in case resident popup window was destroyed. */
1910 if (Wnd
== top_popup
)
1913 top_popup_hmenu
= NULL
;
1920 if (0 == GetWindowLongPtrW(Wnd
, 0))
1922 OutputDebugStringA("no menu to display\n");
1927 SetWindowLongPtrW(Wnd
, 0, 0);
1931 case MM_SETMENUHANDLE
:
1932 SetWindowLongPtrW(Wnd
, 0, wParam
);
1935 case MM_GETMENUHANDLE
:
1937 return GetWindowLongPtrW(Wnd
, 0);
1940 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1946 /**********************************************************************
1947 * MENU_ParseResource
1949 * Parse a standard menu resource and add items to the menu.
1950 * Return a pointer to the end of the resource.
1952 * NOTE: flags is equivalent to the mtOption field
1954 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1963 flags
= GET_WORD(res
);
1965 /* remove MF_END flag before passing it to AppendMenu()! */
1966 end
= (flags
& MF_END
);
1967 if(end
) flags
^= MF_END
;
1969 res
+= sizeof(WORD
);
1970 if(!(flags
& MF_POPUP
))
1973 res
+= sizeof(WORD
);
1977 res
+= strlen(str
) + 1;
1979 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1980 if (flags
& MF_POPUP
)
1982 hSubMenu
= CreatePopupMenu();
1983 if(!hSubMenu
) return NULL
;
1984 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1987 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1989 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1991 else /* Not a popup */
1996 flags
= MF_SEPARATOR
;
2000 if (*(LPCWSTR
)str
== 0)
2001 flags
= MF_SEPARATOR
;
2004 if (flags
& MF_SEPARATOR
)
2006 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2007 flags
|= MF_GRAYED
| MF_DISABLED
;
2011 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2013 AppendMenuW(hMenu
, flags
, id
,
2014 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2021 /**********************************************************************
2022 * MENUEX_ParseResource
2024 * Parse an extended menu resource and add items to the menu.
2025 * Return a pointer to the end of the resource.
2027 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2033 mii
.cbSize
= sizeof(mii
);
2034 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
2035 mii
.fType
= GET_DWORD(res
);
2036 res
+= sizeof(DWORD
);
2037 mii
.fState
= GET_DWORD(res
);
2038 res
+= sizeof(DWORD
);
2039 mii
.wID
= GET_DWORD(res
);
2040 res
+= sizeof(DWORD
);
2041 resinfo
= GET_WORD(res
);
2042 res
+= sizeof(WORD
);
2043 /* Align the text on a word boundary. */
2044 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2045 mii
.dwTypeData
= (LPWSTR
) res
;
2046 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2047 /* Align the following fields on a dword boundary. */
2048 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2050 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2051 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2053 if (resinfo
& 1) { /* Pop-up? */
2054 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2055 res
+= sizeof(DWORD
);
2056 mii
.hSubMenu
= CreatePopupMenu();
2059 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2060 DestroyMenu(mii
.hSubMenu
);
2063 mii
.fMask
|= MIIM_SUBMENU
;
2064 mii
.fType
|= MF_POPUP
;
2065 mii
.wID
= (UINT
) mii
.hSubMenu
;
2067 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
2069 mii
.fType
|= MF_SEPARATOR
;
2071 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2072 } while (!(resinfo
& MF_END
));
2077 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2079 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2080 LRESULT Result
= (LRESULT
)hmenu
;
2081 MENUINFO menuinfo
= {0};
2082 MENUITEMINFOW info
= {0};
2084 // removing space for checkboxes from menu
2085 menuinfo
.cbSize
= sizeof(menuinfo
);
2086 menuinfo
.fMask
= MIM_STYLE
;
2087 GetMenuInfo(hmenu
, &menuinfo
);
2088 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2089 SetMenuInfo(hmenu
, &menuinfo
);
2091 // adding bitmaps to menu items
2092 info
.cbSize
= sizeof(info
);
2093 info
.fMask
|= MIIM_BITMAP
;
2094 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2095 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2096 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2097 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2098 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2099 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2100 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2101 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2103 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2110 NONCLIENTMETRICSW ncm
;
2112 /* get the menu font */
2113 if(!hMenuFont
|| !hMenuFontBold
)
2115 ncm
.cbSize
= sizeof(ncm
);
2116 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2118 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2122 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2123 if(hMenuFont
== NULL
)
2125 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2129 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2130 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2131 if(hMenuFontBold
== NULL
)
2133 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2134 DeleteObject(hMenuFont
);
2148 DeleteObject(hMenuFont
);
2154 DeleteObject(hMenuFontBold
);
2155 hMenuFontBold
= NULL
;
2159 /***********************************************************************
2160 * DrawMenuBarTemp (USER32.@)
2164 * called by W98SE desk.cpl Control Panel Applet
2166 * Not 100% sure about the param names, but close.
2171 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2173 ROSMENUINFO MenuInfo
;
2174 ROSMENUITEMINFO ItemInfo
;
2176 HFONT FontOld
= NULL
;
2177 BOOL flat_menu
= FALSE
;
2179 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2183 Menu
= GetMenu(Wnd
);
2191 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2193 return GetSystemMetrics(SM_CYMENU
);
2196 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2198 FontOld
= SelectObject(DC
, Font
);
2200 if (0 == MenuInfo
.Height
)
2202 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2205 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2207 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2209 SelectObject(DC
, GetStockObject(DC_PEN
));
2210 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2211 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2212 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2214 if (0 == MenuInfo
.MenuItemCount
)
2216 SelectObject(DC
, FontOld
);
2217 return GetSystemMetrics(SM_CYMENU
);
2220 MenuInitRosMenuItemInfo(&ItemInfo
);
2221 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2223 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2225 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2226 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2229 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2231 SelectObject(DC
, FontOld
);
2233 return MenuInfo
.Height
;
2236 /***********************************************************************
2239 * Display the sub-menu of the selected item of this menu.
2240 * Return the handle of the submenu, or menu if no submenu to display.
2242 static HMENU FASTCALL
2243 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2245 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2247 ROSMENUITEMINFO ItemInfo
;
2248 ROSMENUINFO SubMenuInfo
;
2252 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2254 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2256 return MenuInfo
->Self
;
2259 MenuInitRosMenuItemInfo(&ItemInfo
);
2260 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2262 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2263 return MenuInfo
->Self
;
2265 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2267 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2268 return MenuInfo
->Self
;
2271 /* message must be sent before using item,
2272 because nearly everything may be changed by the application ! */
2274 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2275 if (0 == (Flags
& TPM_NONOTIFY
))
2277 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2278 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2281 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2283 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2284 return MenuInfo
->Self
;
2286 Rect
= ItemInfo
.Rect
;
2288 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2289 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2291 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2293 Dc
= GetDC(MenuInfo
->Wnd
);
2297 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2300 SelectObject(Dc
, hMenuFont
);
2301 ItemInfo
.fMask
|= MIIM_STATE
;
2302 ItemInfo
.fState
|= MF_HILITE
;
2303 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2304 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2305 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2306 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2309 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2310 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2312 ItemInfo
.Rect
= Rect
;
2315 ItemInfo
.fMask
|= MIIM_STATE
;
2316 ItemInfo
.fState
|= MF_MOUSESELECT
;
2317 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2319 if (IS_SYSTEM_MENU(MenuInfo
))
2321 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2322 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2324 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2325 Rect
.top
= Rect
.bottom
;
2326 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2327 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2331 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2332 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2334 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2335 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2336 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2337 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2338 - GetSystemMetrics(SM_CYBORDER
);
2342 Rect
.left
+= ItemInfo
.Rect
.left
;
2343 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2344 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2345 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2349 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2350 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2351 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2353 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2356 Ret
= ItemInfo
.hSubMenu
;
2357 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2362 /**********************************************************************
2365 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2367 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2369 void MENU_EndMenu( HWND hwnd
)
2371 ROSMENUINFO MenuInfo
;
2373 if (top_popup_hmenu
)
2374 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2375 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2378 /***********************************************************************
2381 * Hide the sub-popup menus of this menu.
2383 static void FASTCALL
2384 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2385 BOOL SendMenuSelect
, UINT wFlags
)
2387 ROSMENUINFO SubMenuInfo
;
2388 ROSMENUITEMINFO ItemInfo
;
2390 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2392 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2394 MenuInitRosMenuItemInfo(&ItemInfo
);
2395 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2396 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2397 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2398 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2400 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2403 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2404 ItemInfo
.fMask
|= MIIM_STATE
;
2405 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2406 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2408 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2409 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2410 DestroyWindow(SubMenuInfo
.Wnd
);
2411 SubMenuInfo
.Wnd
= NULL
;
2412 MenuSetRosMenuInfo(&SubMenuInfo
);
2414 if (!(wFlags
& TPM_NONOTIFY
))
2415 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2416 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2421 /***********************************************************************
2422 * MenuSwitchTracking
2424 * Helper function for menu navigation routines.
2426 static void FASTCALL
2427 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2429 ROSMENUINFO TopMenuInfo
;
2431 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2433 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2434 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2435 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2437 /* both are top level menus (system and menu-bar) */
2438 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2439 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2440 Mt
->TopMenu
= PtMenuInfo
->Self
;
2444 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2447 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2450 /***********************************************************************
2451 * MenuExecFocusedItem
2453 * Execute a menu item (for instance when user pressed Enter).
2454 * Return the wID of the executed item. Otherwise, -1 indicating
2455 * that no menu item was executed, -2 if a popup is shown;
2456 * Have to receive the flags for the TrackPopupMenu options to avoid
2457 * sending unwanted message.
2461 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2463 ROSMENUITEMINFO ItemInfo
;
2466 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2468 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2473 MenuInitRosMenuItemInfo(&ItemInfo
);
2474 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2476 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2480 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2482 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2484 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2485 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2487 /* If TPM_RETURNCMD is set you return the id, but
2488 do not send a message to the owner */
2489 if (0 == (Flags
& TPM_RETURNCMD
))
2491 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2493 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2494 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2498 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2499 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2500 MenuInfo
->FocusedItem
,
2501 (LPARAM
)MenuInfo
->Self
);
2503 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2507 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2513 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2520 /***********************************************************************
2523 * Return TRUE if we can go on with menu tracking.
2525 static BOOL FASTCALL
2526 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2529 ROSMENUINFO MenuInfo
;
2530 ROSMENUITEMINFO Item
;
2532 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2536 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2540 if (IS_SYSTEM_MENU(&MenuInfo
))
2546 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2548 MenuInitRosMenuItemInfo(&Item
);
2549 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2551 MenuCleanupRosMenuItemInfo(&Item
);
2555 if (!(Item
.fType
& MF_SEPARATOR
) &&
2556 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2558 if (MenuInfo
.FocusedItem
!= Index
)
2560 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2563 /* If the popup menu is not already "popped" */
2564 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2566 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2570 MenuCleanupRosMenuItemInfo(&Item
);
2575 /* else the click was on the menu bar, finish the tracking */
2580 /***********************************************************************
2583 * Return the value of MenuExecFocusedItem if
2584 * the selected item was not a popup. Else open the popup.
2585 * A -1 return value indicates that we go on with menu tracking.
2589 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2592 ROSMENUINFO MenuInfo
;
2593 ROSMENUITEMINFO ItemInfo
;
2595 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2600 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2605 if (! IS_SYSTEM_MENU(&MenuInfo
))
2607 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2609 MenuInitRosMenuItemInfo(&ItemInfo
);
2610 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2611 MenuInfo
.FocusedItem
== Id
)
2613 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2615 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2616 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2617 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2619 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2621 /* If we are dealing with the top-level menu */
2622 /* and this is a click on an already "popped" item: */
2623 /* Stop the menu tracking and close the opened submenus */
2624 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2626 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2630 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2631 MenuInfo
.TimeToHide
= TRUE
;
2632 MenuSetRosMenuInfo(&MenuInfo
);
2638 /***********************************************************************
2641 * Walks menu chain trying to find a menu pt maps to.
2643 static HMENU FASTCALL
2644 MenuPtMenu(HMENU Menu
, POINT Pt
)
2646 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2647 ROSMENUINFO MenuInfo
;
2648 ROSMENUITEMINFO ItemInfo
;
2652 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2657 /* try subpopup first (if any) */
2658 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2660 MenuInitRosMenuItemInfo(&ItemInfo
);
2661 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2662 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2663 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2665 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2668 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2672 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2675 /* check the current window (avoiding WM_HITTEST) */
2676 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2677 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2679 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2684 else if (HTSYSMENU
== Ht
)
2686 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2688 else if (HTMENU
== Ht
)
2690 Ret
= GetMenu(MenuInfo
.Wnd
);
2696 /***********************************************************************
2699 * Return TRUE if we can go on with menu tracking.
2701 static BOOL FASTCALL
2702 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2705 ROSMENUINFO MenuInfo
;
2706 ROSMENUITEMINFO ItemInfo
;
2710 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2714 if (IS_SYSTEM_MENU(&MenuInfo
))
2720 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2725 Index
= NO_SELECTED_ITEM
;
2728 if (NO_SELECTED_ITEM
== Index
)
2730 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2731 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2733 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2737 else if (MenuInfo
.FocusedItem
!= Index
)
2739 MenuInitRosMenuItemInfo(&ItemInfo
);
2740 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2741 !(ItemInfo
.fType
& MF_SEPARATOR
))
2743 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2744 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2745 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2747 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2753 /***********************************************************************
2756 * Return the handle of the selected sub-popup menu (if any).
2758 static HMENU FASTCALL
2759 MenuGetSubPopup(HMENU Menu
)
2761 ROSMENUINFO MenuInfo
;
2762 ROSMENUITEMINFO ItemInfo
;
2764 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2765 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2770 MenuInitRosMenuItemInfo(&ItemInfo
);
2771 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2773 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2776 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2778 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2779 return ItemInfo
.hSubMenu
;
2782 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2786 /***********************************************************************
2789 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2791 static LRESULT FASTCALL
2792 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2794 ROSMENUINFO TopMenuInfo
;
2795 ROSMENUINFO MenuInfo
;
2797 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2799 return (LRESULT
) FALSE
;
2802 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2803 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2805 MDINEXTMENU NextMenu
;
2810 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2811 NextMenu
.hmenuNext
= NULL
;
2812 NextMenu
.hwndNext
= NULL
;
2813 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2815 TRACE("%p [%p] -> %p [%p]\n",
2816 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2818 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2820 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2821 NewWnd
= Mt
->OwnerWnd
;
2822 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2824 /* switch to the menu bar */
2826 if (0 != (Style
& WS_CHILD
)
2827 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2834 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2838 Id
= MenuInfo
.MenuItemCount
- 1;
2841 else if (0 != (Style
& WS_SYSMENU
))
2843 /* switch to the system menu */
2844 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2851 else /* application returned a new menu to switch to */
2853 NewMenu
= NextMenu
.hmenuNext
;
2854 NewWnd
= NextMenu
.hwndNext
;
2856 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2858 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2860 if (0 != (Style
& WS_SYSMENU
)
2861 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2863 /* get the real system menu */
2864 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2866 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2868 /* FIXME: Not sure what to do here;
2869 * perhaps try to track NewMenu as a popup? */
2871 WARN(" -- got confused.\n");
2881 if (NewMenu
!= Mt
->TopMenu
)
2883 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2885 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2887 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2891 if (NewWnd
!= Mt
->OwnerWnd
)
2893 Mt
->OwnerWnd
= NewWnd
;
2894 SetCapture(Mt
->OwnerWnd
);
2895 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2898 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2899 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2901 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2910 /***********************************************************************
2913 * The idea is not to show the popup if the next input message is
2914 * going to hide it anyway.
2916 static BOOL FASTCALL
2917 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2921 Msg
.hwnd
= Mt
->OwnerWnd
;
2923 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2924 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2929 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2930 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2932 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2933 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2934 if (WM_KEYDOWN
== Msg
.message
2935 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2937 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2944 /* failures go through this */
2945 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2950 /***********************************************************************
2953 * Handle a VK_ESCAPE key event in a menu.
2955 static BOOL FASTCALL
2956 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2958 BOOL EndMenu
= TRUE
;
2959 ROSMENUINFO MenuInfo
;
2960 HMENU MenuTmp
, MenuPrev
;
2962 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2964 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2965 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2967 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2969 /* close topmost popup */
2970 while (MenuTmp
!= Mt
->CurrentMenu
)
2973 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2976 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2978 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
2980 Mt
->CurrentMenu
= MenuPrev
;
2988 /***********************************************************************
2991 * Handle a VK_LEFT key event in a menu.
2993 static void FASTCALL
2994 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2996 ROSMENUINFO MenuInfo
;
2997 ROSMENUINFO TopMenuInfo
;
2998 ROSMENUINFO PrevMenuInfo
;
2999 HMENU MenuTmp
, MenuPrev
;
3002 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3004 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3009 /* Try to move 1 column left (if possible) */
3010 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3012 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3014 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3019 /* close topmost popup */
3020 while (MenuTmp
!= Mt
->CurrentMenu
)
3023 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3026 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3030 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3031 Mt
->CurrentMenu
= MenuPrev
;
3033 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3037 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3039 /* move menu bar selection if no more popups are left */
3041 if (! MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3043 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3046 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3048 /* A sublevel menu was displayed - display the next one
3049 * unless there is another displacement coming up */
3051 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3052 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3054 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3061 /***********************************************************************
3064 * Handle a VK_RIGHT key event in a menu.
3066 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3069 ROSMENUINFO MenuInfo
;
3070 ROSMENUINFO CurrentMenuInfo
;
3073 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3074 Mt
->CurrentMenu
, Mt
->TopMenu
);
3076 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3077 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3079 /* If already displaying a popup, try to display sub-popup */
3081 hmenutmp
= Mt
->CurrentMenu
;
3082 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3084 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3087 /* if subpopup was displayed then we are done */
3088 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3091 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3096 /* Check to see if there's another column */
3097 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3099 TRACE("Going to %d.\n", NextCol
);
3100 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3102 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3107 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3109 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3111 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3112 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3119 /* try to move to the next item */
3120 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3121 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3123 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3125 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3126 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3128 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3135 /***********************************************************************
3138 * Menu tracking code.
3140 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3141 HWND hwnd
, const RECT
*lprect
)
3144 ROSMENUINFO MenuInfo
;
3145 ROSMENUITEMINFO ItemInfo
;
3147 INT executedMenuId
= -1;
3149 BOOL enterIdleSent
= FALSE
;
3152 mt
.CurrentMenu
= hmenu
;
3158 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3159 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3160 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3164 WARN("Invalid menu handle %p\n", hmenu
);
3165 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3170 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3175 if (wFlags
& TPM_BUTTONDOWN
)
3177 /* Get the result in order to start the tracking or not */
3178 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3179 fEndMenu
= !fRemove
;
3182 SetCapture(mt
.OwnerWnd
);
3183 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, mt
.OwnerWnd
);
3185 ERR("MenuTrackMenu 1\n");
3188 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, VALIDATE_TYPE_MENU
);
3189 if (!menu
) /* sometimes happens if I do a window manager close */
3192 /* we have to keep the message in the queue until it's
3193 * clear that menu loop is not over yet. */
3197 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3199 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3200 /* remove the message from the queue */
3201 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3207 HWND win
= MenuInfo
.Flags
& MF_POPUP
? MenuInfo
.Wnd
: NULL
;
3208 enterIdleSent
= TRUE
;
3209 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3215 /* check if EndMenu() tried to cancel us, by posting this message */
3216 if (msg
.message
== WM_CANCELMODE
)
3218 /* we are now out of the loop */
3221 /* remove the message from the queue */
3222 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3224 /* break out of internal loop, ala ESCAPE */
3228 TranslateMessage( &msg
);
3231 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3232 enterIdleSent
=FALSE
;
3235 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3238 * Use the mouse coordinates in lParam instead of those in the MSG
3239 * struct to properly handle synthetic messages. They are already
3240 * in screen coordinates.
3242 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3243 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3245 /* Find a menu for this mouse event */
3246 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3250 /* no WM_NC... messages in captured state */
3252 case WM_RBUTTONDBLCLK
:
3253 case WM_RBUTTONDOWN
:
3254 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3256 case WM_LBUTTONDBLCLK
:
3257 case WM_LBUTTONDOWN
:
3258 /* If the message belongs to the menu, removes it from the queue */
3259 /* Else, end menu tracking */
3260 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3261 fEndMenu
= !fRemove
;
3265 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3268 /* Check if a menu was selected by the mouse */
3271 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3272 TRACE("executedMenuId %d\n", executedMenuId
);
3274 /* End the loop if executedMenuId is an item ID */
3275 /* or if the job was done (executedMenuId = 0). */
3276 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3278 /* No menu was selected by the mouse */
3279 /* if the function was called by TrackPopupMenu, continue
3280 with the menu tracking. If not, stop it */
3282 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3287 /* the selected menu item must be changed every time */
3288 /* the mouse moves. */
3291 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3293 } /* switch(msg.message) - mouse */
3295 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3297 fRemove
= TRUE
; /* Keyboard messages are always removed */
3311 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3313 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
3314 NO_SELECTED_ITEM
, FALSE
, 0 );
3315 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3316 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3321 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3322 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3324 if (!(MenuInfo
.Flags
& MF_POPUP
))
3326 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3327 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3329 else /* otherwise try to move selection */
3330 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3331 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3336 MenuKeyLeft( &mt
, wFlags
);
3340 MenuKeyRight( &mt
, wFlags
);
3344 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3350 hi
.cbSize
= sizeof(HELPINFO
);
3351 hi
.iContextType
= HELPINFO_MENUITEM
;
3352 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3354 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
)
3358 MenuInitRosMenuItemInfo(&ItemInfo
);
3359 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3360 MenuInfo
.FocusedItem
,
3363 hi
.iCtrlId
= ItemInfo
.wID
;
3369 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3372 hi
.hItemHandle
= hmenu
;
3373 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3374 hi
.MousePos
= msg
.pt
;
3375 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3382 break; /* WM_KEYDOWN */
3389 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3390 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3392 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3393 fEndMenu
= (executedMenuId
!= -2);
3397 /* Hack to avoid control chars. */
3398 /* We will find a better way real soon... */
3399 if (msg
.wParam
< 32) break;
3401 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3402 LOWORD(msg
.wParam
), FALSE
);
3403 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3404 else if (pos
== (UINT
)-1) MessageBeep(0);
3407 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3409 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3410 fEndMenu
= (executedMenuId
!= -2);
3414 } /* switch(msg.message) - kbd */
3418 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3419 DispatchMessageW( &msg
);
3423 if (!fEndMenu
) fRemove
= TRUE
;
3425 /* finally remove message from the queue */
3427 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3428 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3429 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3431 ERR("MenuTrackMenu 2\n");
3433 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3434 SetCapture(NULL
); /* release the capture */
3436 /* If dropdown is still painted and the close box is clicked on
3437 then the menu will be destroyed as part of the DispatchMessage above.
3438 This will then invalidate the menu handle in mt.hTopMenu. We should
3439 check for this first. */
3440 if( IsMenu( mt
.TopMenu
) )
3442 if (IsWindow(mt
.OwnerWnd
))
3444 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3446 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3448 if (MenuInfo
.Flags
& MF_POPUP
)
3450 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3451 DestroyWindow(MenuInfo
.Wnd
);
3452 MenuInfo
.Wnd
= NULL
;
3454 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3455 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3456 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3459 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3462 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3465 /* Reset the variable for hiding menu */
3466 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3468 MenuInfo
.TimeToHide
= FALSE
;
3469 MenuSetRosMenuInfo(&MenuInfo
);
3473 /* The return value is only used by TrackPopupMenu */
3474 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3475 if (executedMenuId
== -1) executedMenuId
= 0;
3476 return executedMenuId
;
3479 /***********************************************************************
3482 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3484 ROSMENUINFO MenuInfo
;
3486 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3490 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3491 if (!(wFlags
& TPM_NONOTIFY
))
3492 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3494 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3496 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
3498 if (!(wFlags
& TPM_NONOTIFY
))
3500 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3501 /* If an app changed/recreated menu bar entries in WM_INITMENU
3502 * menu sizes will be recalculated once the menu created/shown.
3505 if (!MenuInfo
.Height
)
3507 /* app changed/recreated menu bar entries in WM_INITMENU
3508 Recalculate menu sizes else clicks will not work */
3509 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3510 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3515 /* This makes the menus of applications built with Delphi work.
3516 * It also enables menus to be displayed in more than one window,
3517 * but there are some bugs left that need to be fixed in this case.
3519 if(MenuInfo
.Self
== hMenu
)
3521 MenuInfo
.Wnd
= hWnd
;
3522 MenuSetRosMenuInfo(&MenuInfo
);
3525 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
3527 MenuInfo
.Flags
& MF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
3531 /***********************************************************************
3534 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
3536 TRACE("hwnd=%p\n", hWnd
);
3538 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
3539 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
3542 top_popup_hmenu
= NULL
;
3546 /***********************************************************************
3547 * MenuTrackMouseMenuBar
3549 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3551 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3553 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3554 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3556 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3560 /* map point to parent client coordinates */
3561 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3562 if (Parent
!= GetDesktopWindow())
3564 ScreenToClient(Parent
, &pt
);
3567 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3568 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3569 MenuExitTracking(hWnd
, FALSE
);
3574 /***********************************************************************
3575 * MenuTrackKbdMenuBar
3577 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3579 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3581 UINT uItem
= NO_SELECTED_ITEM
;
3583 ROSMENUINFO MenuInfo
;
3584 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3586 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3588 /* find window that has a menu */
3590 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3591 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3592 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3594 /* check if we have to track a system menu */
3596 hTrackMenu
= GetMenu( hwnd
);
3597 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3599 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3600 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3602 wParam
|= HTSYSMENU
; /* prevent item lookup */
3605 if (!IsMenu( hTrackMenu
)) return;
3607 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3609 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3614 if( wChar
&& wChar
!= ' ' )
3616 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3617 if ( uItem
>= (UINT
)(-2) )
3619 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3620 /* schedule end of menu tracking */
3621 wFlags
|= TF_ENDMENU
;
3626 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3628 if (wParam
& HTSYSMENU
)
3630 /* prevent sysmenu activation for managed windows on Alt down/up */
3631 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3632 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3636 if( uItem
== NO_SELECTED_ITEM
)
3637 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3639 PostMessageW( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3643 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3644 MenuExitTracking( hwnd
, FALSE
);
3648 /**********************************************************************
3649 * TrackPopupMenuEx (USER32.@)
3651 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
3652 HWND Wnd
, LPTPMPARAMS Tpm
)
3658 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3662 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
3664 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3665 if (!(Flags
& TPM_NONOTIFY
))
3666 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
3668 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
3669 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
3670 Tpm
? &Tpm
->rcExclude
: NULL
);
3671 MenuExitTracking(Wnd
, TRUE
);
3675 /**********************************************************************
3676 * TrackPopupMenu (USER32.@)
3678 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
3679 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
3681 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
3686 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3687 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3689 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3691 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3692 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3693 * MFT_STRING is replaced by MIIM_STRING.
3694 * (So, I guess we should use MIIM_STRING only for strings?)
3696 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3698 * Based on wine, SetMenuItemInfo_common:
3699 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3700 * it will result in a error.
3701 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3702 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3709 LPMENUITEMINFOW mii
,
3716 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3718 if(Flags
& MF_BITMAP
)
3720 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3721 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3723 if (Flags
& MF_HELP
)
3725 /* increase ident */
3726 mii
->fType
|= MF_HELP
;
3729 else if(Flags
& MF_OWNERDRAW
)
3731 mii
->fType
|= MFT_OWNERDRAW
;
3732 mii
->fMask
|= MIIM_DATA
;
3733 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
3735 else if (Flags
& MF_SEPARATOR
)
3737 mii
->fType
|= MFT_SEPARATOR
;
3738 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3739 Flags
|= MF_GRAYED
|MF_DISABLED
;
3741 else /* Default action MF_STRING. */
3743 /* Item beginning with a backspace is a help item */
3744 if (NewItem
!= NULL
)
3748 if (*NewItem
== '\b')
3750 mii
->fType
|= MF_HELP
;
3756 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3757 if (*NewItemA
== '\b')
3759 mii
->fType
|= MF_HELP
;
3761 NewItem
= (LPCWSTR
) NewItemA
;
3765 if (Flags
& MF_HELP
)
3766 mii
->fType
|= MF_HELP
;
3767 mii
->fMask
|= MIIM_STRING
;
3768 mii
->fType
|= MFT_STRING
; /* Zero */
3769 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3771 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3773 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3777 mii
->fType
|= MFT_SEPARATOR
;
3778 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3779 Flags
|= MF_GRAYED
|MF_DISABLED
;
3783 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3785 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3788 if(Flags
& MF_MENUBREAK
)
3790 mii
->fType
|= MFT_MENUBREAK
;
3792 else if(Flags
& MF_MENUBARBREAK
)
3794 mii
->fType
|= MFT_MENUBARBREAK
;
3797 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3799 if (Flags
& MF_GRAYED
)
3800 mii
->fState
|= MF_GRAYED
;
3802 if (Flags
& MF_DISABLED
)
3803 mii
->fState
|= MF_DISABLED
;
3805 mii
->fMask
|= MIIM_STATE
;
3807 else if (Flags
& MF_HILITE
)
3809 mii
->fState
|= MF_HILITE
;
3810 mii
->fMask
|= MIIM_STATE
;
3812 else /* default state */
3814 mii
->fState
|= MFS_ENABLED
;
3815 mii
->fMask
|= MIIM_STATE
;
3818 if(Flags
& MF_POPUP
)
3820 mii
->fType
|= MF_POPUP
;
3821 mii
->fMask
|= MIIM_SUBMENU
;
3822 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3826 mii
->fMask
|= MIIM_ID
;
3827 mii
->wID
= (UINT
)IDNewItem
;
3833 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3835 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3838 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3840 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3841 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3842 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3843 (LPCWSTR
)&Common
->MenuName
);
3845 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3849 /* FUNCTIONS *****************************************************************/
3852 MenuIsStringItem(ULONG TypeData)
3854 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3862 AppendMenuA(HMENU hMenu
,
3864 UINT_PTR uIDNewItem
,
3867 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3876 AppendMenuW(HMENU hMenu
,
3878 UINT_PTR uIDNewItem
,
3881 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3890 CheckMenuItem(HMENU hmenu
,
3894 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3899 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3902 PROSMENUITEMINFO Items
= NULL
;
3903 UINT cChecked
, cUnchecked
;
3907 if(idFirst
> idLast
)
3910 ItemCount
= GetMenuItemCount(hMenu
);
3912 //mi.cbSize = sizeof(ROSMENUINFO);
3913 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3916 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3918 ERR("MenuGetAllRosMenuItemInfo failed\n");
3922 cChecked
= cUnchecked
= 0;
3924 for (i
= 0 ; i
< ItemCount
; i
++)
3927 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3928 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3930 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3932 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3935 if (uFlags
& MF_BYPOSITION
)
3937 if (i
< idFirst
|| i
> idLast
)
3952 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3955 if (Items
[i
].wID
== idCheck
)
3969 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
3972 Items
[i
].fType
|= MFT_RADIOCHECK
;
3973 Items
[i
].fState
|= MFS_CHECKED
;
3977 Items
[i
].fState
&= ~MFS_CHECKED
;
3980 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
3982 ERR("MenuSetRosMenuItemInfo failed\n");
3987 HeapFree(GetProcessHeap(), 0, Items
);
3989 *pChecked
+= cChecked
;
3990 *pUnchecked
+= cUnchecked
;
3992 if (cChecked
|| cUnchecked
)
4002 CheckMenuRadioItem(HMENU hmenu
,
4009 UINT cUnchecked
= 0;
4010 UINT cMenuChanged
= 0;
4012 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4015 if (cMenuChanged
> 1)
4022 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4025 return (cChecked
!= 0);
4036 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4044 CreatePopupMenu(VOID
)
4047 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4055 DrawMenuBar(HWND hWnd
)
4057 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4058 ROSMENUINFO MenuInfo
;
4060 hMenu
= GetMenu(hWnd
);
4063 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4064 MenuInfo
.Height
= 0; // make sure to recalc size
4065 MenuSetRosMenuInfo(&MenuInfo
);
4066 /* The wine method doesn't work and I suspect it's more effort
4067 then hackfix solution
4068 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4069 SWP_NOZORDER | SWP_FRAMECHANGED );
4072 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4080 EnableMenuItem(HMENU hMenu
,
4084 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4094 guii
.cbSize
= sizeof(GUITHREADINFO
);
4095 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4099 guii
.hwndMenuOwner
!= top_popup
)
4101 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4105 /* if we are in the menu code, and it is active */
4106 if (!fEndMenu
&& top_popup
)
4108 /* terminate the menu handling code */
4111 /* needs to be posted to wakeup the internal menu handler */
4112 /* which will now terminate the menu, in the event that */
4113 /* the main window was minimized, or lost focus, so we */
4114 /* don't end up with an orphaned menu */
4115 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4120 // So this one maybe one day it will be a callback!
4121 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4124 ROSMENUINFO MenuInfo
;
4125 ROSMENUITEMINFO mii
;
4126 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4129 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4132 if (!NtUserMenuItemInfo(hMenu
, wItemID
, wHilite
, &mii
, FALSE
)) return FALSE
;
4133 if (!NtUserMenuInfo(hMenu
, &MenuInfo
, FALSE
)) return FALSE
;
4134 if (MenuInfo
.FocusedItem
== wItemID
) return TRUE
;
4135 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4136 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4146 PWND Wnd
= ValidateHwnd(hWnd
);
4151 return UlongToHandle(Wnd
->IDMenu
);
4159 GetMenuCheckMarkDimensions(VOID
)
4161 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4162 GetSystemMetrics(SM_CYMENUCHECK
)));
4170 GetMenuDefaultItem(HMENU hMenu
,
4174 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4182 GetMenuInfo(HMENU hmenu
,
4188 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4191 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4192 mi
.cbSize
= sizeof(MENUINFO
);
4193 mi
.fMask
= lpcmi
->fMask
;
4195 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4197 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4206 GetMenuItemCount(HMENU Menu
)
4208 ROSMENUINFO MenuInfo
;
4210 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4218 GetMenuItemID(HMENU hMenu
,
4221 ROSMENUITEMINFO mii
;
4223 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4224 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4226 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4231 if (NULL
!= mii
.hSubMenu
)
4252 LPMENUITEMINFOA mii
)
4258 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4259 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4261 SetLastError(ERROR_INVALID_PARAMETER
);
4265 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4267 /* No text requested, just pass on */
4268 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4271 AnsiBuffer
= mii
->dwTypeData
;
4272 Count
= miiW
.cch
= mii
->cch
;
4273 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4274 miiW
.dwTypeData
= 0;
4278 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4279 miiW
.cch
* sizeof(WCHAR
));
4280 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4281 miiW
.dwTypeData
[0] = 0;
4284 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4286 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4290 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4292 if (!AnsiBuffer
|| !Count
)
4294 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4295 mii
->dwTypeData
= AnsiBuffer
;
4296 mii
->cch
= miiW
.cch
;
4300 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4304 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4308 if (Count
> miiW
.cch
)
4310 AnsiBuffer
[miiW
.cch
] = 0;
4312 mii
->cch
= mii
->cch
;
4320 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4321 mii
->dwTypeData
= AnsiBuffer
;
4335 LPMENUITEMINFOW mii
)
4341 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4342 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4344 SetLastError(ERROR_INVALID_PARAMETER
);
4348 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4350 /* No text requested, just pass on */
4351 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4354 String
= mii
->dwTypeData
;
4356 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4357 miiW
.dwTypeData
= 0;
4361 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4362 miiW
.cch
* sizeof(WCHAR
));
4363 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4364 miiW
.dwTypeData
[0] = 0;
4367 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4369 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4373 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4375 if (!String
|| !Count
)
4377 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4378 mii
->dwTypeData
= String
; // may not be zero.
4379 mii
->cch
= miiW
.cch
;
4383 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4385 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4388 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4389 mii
->dwTypeData
= String
;
4390 mii
->cch
= strlenW(String
);
4405 ROSMENUINFO MenuInfo
;
4406 ROSMENUITEMINFO mii
;
4407 memset( &mii
, 0, sizeof(mii
) );
4408 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4409 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4412 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4417 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4421 nSubItems
= MenuInfo
.MenuItemCount
;
4423 /* FIXME - ported from wine, does that work (0xff)? */
4424 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4425 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4427 return (UINT
)-1; /* Invalid submenu */
4430 /* FIXME - ported from wine, does that work? */
4431 return (mii
.fType
| mii
.fState
);
4451 memset( &mii
, 0, sizeof(mii
) );
4452 mii
.dwTypeData
= lpString
;
4453 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4454 mii
.fType
= MFT_STRING
;
4455 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4456 mii
.cch
= nMaxCount
;
4458 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4478 memset( &miiW
, 0, sizeof(miiW
) );
4479 miiW
.dwTypeData
= lpString
;
4480 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4481 miiW
.fType
= MFT_STRING
;
4482 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4483 miiW
.cch
= nMaxCount
;
4485 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4503 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4504 mi
.fMask
= MIIM_SUBMENU
;
4506 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4508 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4525 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4527 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4540 UINT_PTR uIDNewItem
,
4544 memset( &mii
, 0, sizeof(mii
) );
4545 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4546 mii
.fMask
= MIIM_FTYPE
;
4548 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4551 (LPCWSTR
) lpNewItem
,
4554 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4568 LPCMENUITEMINFOA lpmii
)
4571 UNICODE_STRING MenuText
;
4573 BOOL CleanHeap
= FALSE
;
4576 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4577 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4579 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4581 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4583 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4586 /* copy the text string */
4587 if (((mi
.fMask
& MIIM_STRING
) ||
4588 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4589 && mi
.dwTypeData
!= NULL
)
4591 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4592 if (!NT_SUCCESS (Status
))
4594 SetLastError (RtlNtStatusToDosError(Status
));
4597 mi
.dwTypeData
= MenuText
.Buffer
;
4598 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4601 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4603 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4618 LPCMENUITEMINFOW lpmii
)
4621 UNICODE_STRING MenuText
;
4624 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4625 if a bad user passes bad data, we crash his process instead of the
4628 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4629 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4631 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4633 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4635 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4638 /* copy the text string */
4639 if (((mi
.fMask
& MIIM_STRING
) ||
4640 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4641 && mi
.dwTypeData
!= NULL
)
4643 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4644 mi
.dwTypeData
= MenuText
.Buffer
;
4645 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4647 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4662 UINT_PTR uIDNewItem
,
4666 memset( &mii
, 0, sizeof(mii
) );
4667 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4668 mii
.fMask
= MIIM_FTYPE
;
4670 MenuSetItemData( &mii
,
4676 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4688 if (ValidateHandle(Menu
, VALIDATE_TYPE_MENU
)) return TRUE
;
4697 LoadMenuA(HINSTANCE hInstance
,
4700 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4701 if (Resource
== NULL
)
4705 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4713 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4715 return(LoadMenuIndirectW(lpMenuTemplate
));
4723 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4726 WORD version
, offset
;
4727 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4729 version
= GET_WORD(p
);
4734 case 0: /* standard format is version of 0 */
4735 offset
= GET_WORD(p
);
4736 p
+= sizeof(WORD
) + offset
;
4737 if (!(hMenu
= CreateMenu())) return 0;
4738 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4744 case 1: /* extended format is version of 1 */
4745 offset
= GET_WORD(p
);
4746 p
+= sizeof(WORD
) + offset
;
4747 if (!(hMenu
= CreateMenu())) return 0;
4748 if (!MENUEX_ParseResource(p
, hMenu
))
4750 DestroyMenu( hMenu
);
4755 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4765 LoadMenuW(HINSTANCE hInstance
,
4768 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4769 if (Resource
== NULL
)
4773 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4787 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4800 UINT_PTR uIDNewItem
,
4804 ROSMENUITEMINFO rmii
;
4806 memset( &mii
, 0, sizeof(mii
) );
4807 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4808 mii
.fMask
= MIIM_FTYPE
;
4810 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4814 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4816 MenuInitRosMenuItemInfo( &rmii
);
4818 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4820 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4821 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4823 MenuCleanupRosMenuItemInfo( &rmii
);
4825 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4828 (LPCWSTR
) lpNewItem
,
4831 return SetMenuItemInfoA( hMnu
,
4833 (BOOL
)(MF_BYPOSITION
& uFlags
),
4847 UINT_PTR uIDNewItem
,
4851 ROSMENUITEMINFO rmii
;
4853 memset ( &mii
, 0, sizeof(mii
) );
4854 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4855 mii
.fMask
= MIIM_FTYPE
;
4857 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4859 mi
.Height
= 0; // Force size recalculation.
4861 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4863 MenuInitRosMenuItemInfo( &rmii
);
4865 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4867 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4868 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4870 MenuCleanupRosMenuItemInfo( &rmii
);
4872 /* Init new data for this menu item */
4873 MenuSetItemData( &mii
,
4879 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4880 return SetMenuItemInfoW( hMnu
,
4882 (BOOL
)(MF_BYPOSITION
& uFlags
),
4894 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4910 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4912 SetLastError(ERROR_INVALID_PARAMETER
);
4916 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4917 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4930 HBITMAP hBitmapUnchecked
,
4931 HBITMAP hBitmapChecked
)
4933 ROSMENUITEMINFO uItem
;
4934 memset ( &uItem
, 0, sizeof(uItem
) );
4935 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4937 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4938 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4940 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4942 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4944 else /* Install new bitmaps */
4946 uItem
.hbmpChecked
= hBitmapChecked
;
4947 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4948 uItem
.fState
|= MF_USECHECKBITMAPS
;
4950 return NtUserMenuItemInfo(hMenu
, uPosition
,
4951 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4964 LPCMENUITEMINFOA lpmii
)
4966 MENUITEMINFOW MenuItemInfoW
;
4967 UNICODE_STRING UnicodeString
;
4969 ULONG Result
= FALSE
;
4971 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4973 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4975 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4976 MenuItemInfoW
.hbmpItem
= NULL
;
4979 * MIIM_STRING == good
4980 * MIIM_TYPE & MFT_STRING == good
4981 * MIIM_STRING & MFT_STRING == good
4982 * MIIM_STRING & MFT_OWNERSRAW == good
4984 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4985 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4986 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4987 && MenuItemInfoW
.dwTypeData
!= NULL
)
4989 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
4990 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
4991 (LPSTR
)MenuItemInfoW
.dwTypeData
);
4992 if (!NT_SUCCESS (Status
))
4994 SetLastError (RtlNtStatusToDosError(Status
));
4997 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
4998 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5002 UnicodeString
.Buffer
= NULL
;
5005 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5006 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5008 if (UnicodeString
.Buffer
!= NULL
)
5010 RtlFreeUnicodeString(&UnicodeString
);
5026 LPCMENUITEMINFOW lpmii
)
5028 MENUITEMINFOW MenuItemInfoW
;
5031 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5033 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5035 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5036 MenuItemInfoW
.hbmpItem
= NULL
;
5039 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5040 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5041 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5042 && MenuItemInfoW
.dwTypeData
!= NULL
)
5044 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5046 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5047 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5063 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5068 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5071 return NtUserSetSystemMenu(hwnd
, hMenu
);
5075 // Example for the Win32/User32 rewrite.
5076 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5090 return NtUserTrackPopupMenuEx( Menu
,
5095 NULL
); // LPTPMPARAMS is null
5104 GetMenuContextHelpId(HMENU hmenu
)
5107 mi
.cbSize
= sizeof(ROSMENUINFO
);
5108 mi
.fMask
= MIM_HELPID
;
5110 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5112 return mi
.dwContextHelpID
;
5133 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5136 Result
= (ULONG_PTR
)lResult
;
5141 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5161 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5164 Result
= (ULONG_PTR
)lResult
;
5169 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5180 LPCWSTR lpszNewItem
,
5185 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5186 for MF_DELETE. We should check the parameters for all others
5187 MF_* actions also (anybody got a doc on ChangeMenu?).
5190 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5193 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5196 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5199 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5202 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5203 flags
&~ MF_REMOVE
);
5205 default : /* MF_INSERT */
5206 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5223 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5224 for MF_DELETE. We should check the parameters for all others
5225 MF_* actions also (anybody got a doc on ChangeMenu?).
5228 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5231 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5234 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5237 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5240 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5241 flags
&~ MF_REMOVE
);
5243 default : /* MF_INSERT */
5244 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);