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
.rcWork
.right
)
1610 if( xanchor
&& x
>= width
- xanchor
)
1611 x
-= width
- xanchor
;
1613 if( x
+ width
> info
.rcWork
.right
)
1614 x
= info
.rcWork
.right
- width
;
1616 if( x
< info
.rcWork
.left
) x
= info
.rcWork
.left
;
1618 if( y
+ height
> info
.rcWork
.bottom
)
1620 if( yanchor
&& y
>= height
+ yanchor
)
1621 y
-= height
+ yanchor
;
1623 if( y
+ height
> info
.rcWork
.bottom
)
1624 y
= info
.rcWork
.bottom
- height
;
1626 if( y
< info
.rcWork
.top
) y
= info
.rcWork
.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 /* Display the window */
1641 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1642 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1643 UpdateWindow( MenuInfo
.Wnd
);
1648 /***********************************************************************
1651 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1652 BOOL sendMenuSelect
, HMENU topmenu
)
1654 ROSMENUITEMINFO ItemInfo
;
1655 ROSMENUINFO TopMenuInfo
;
1658 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1660 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1661 if (hmenu
->FocusedItem
== wIndex
) return;
1662 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1663 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1665 top_popup
= hmenu
->Wnd
;
1666 top_popup_hmenu
= hmenu
->Self
;
1669 SelectObject( hdc
, hMenuFont
);
1671 MenuInitRosMenuItemInfo(&ItemInfo
);
1673 /* Clear previous highlighted item */
1674 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1676 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1678 ItemInfo
.fMask
|= MIIM_STATE
;
1679 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1680 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1682 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1683 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1687 /* Highlight new item (if any) */
1688 hmenu
->FocusedItem
= wIndex
;
1689 MenuSetRosMenuInfo(hmenu
);
1690 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1692 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1694 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1696 ItemInfo
.fMask
|= MIIM_STATE
;
1697 ItemInfo
.fState
|= MF_HILITE
;
1698 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1699 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1700 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1705 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1706 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1707 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1708 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1712 else if (sendMenuSelect
) {
1715 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1716 if (pos
!= NO_SELECTED_ITEM
)
1718 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1719 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1721 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1722 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1724 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1730 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1731 ReleaseDC(hmenu
->Wnd
, hdc
);
1734 /***********************************************************************
1737 * Moves currently selected item according to the Offset parameter.
1738 * If there is no selection then it should select the last item if
1739 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1741 static void FASTCALL
1742 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1745 ROSMENUITEMINFO ItemInfo
;
1748 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1750 /* Prevent looping */
1751 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1753 else if (Offset
< -1)
1755 else if (Offset
> 1)
1758 MenuInitRosMenuItemInfo(&ItemInfo
);
1760 OrigPos
= MenuInfo
->FocusedItem
;
1761 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1768 i
= MenuInfo
->FocusedItem
;
1775 /* Clip and wrap around */
1778 i
= MenuInfo
->MenuItemCount
- 1;
1780 else if (i
>= MenuInfo
->MenuItemCount
)
1784 /* If this is a good candidate; */
1785 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1786 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1788 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1789 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1792 } while (i
!= OrigPos
);
1795 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1798 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1800 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1806 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1807 SetWindowLongPtrA(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1811 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1812 return MA_NOACTIVATE
;
1817 BeginPaint(Wnd
, &ps
);
1818 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1823 case WM_PRINTCLIENT
:
1825 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1826 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1834 /* zero out global pointer in case resident popup window was destroyed. */
1835 if (Wnd
== top_popup
)
1838 top_popup_hmenu
= NULL
;
1845 if (0 == GetWindowLongPtrA(Wnd
, 0))
1847 OutputDebugStringA("no menu to display\n");
1852 SetWindowLongPtrA(Wnd
, 0, 0);
1856 case MM_SETMENUHANDLE
:
1857 SetWindowLongPtrA(Wnd
, 0, wParam
);
1860 case MM_GETMENUHANDLE
:
1862 return GetWindowLongPtrA(Wnd
, 0);
1865 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1871 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1873 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1879 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1880 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1884 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1885 return MA_NOACTIVATE
;
1890 BeginPaint(Wnd
, &ps
);
1891 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1896 case WM_PRINTCLIENT
:
1898 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1899 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1907 /* zero out global pointer in case resident popup window was destroyed. */
1908 if (Wnd
== top_popup
)
1911 top_popup_hmenu
= NULL
;
1918 if (0 == GetWindowLongPtrW(Wnd
, 0))
1920 OutputDebugStringA("no menu to display\n");
1925 SetWindowLongPtrW(Wnd
, 0, 0);
1929 case MM_SETMENUHANDLE
:
1930 SetWindowLongPtrW(Wnd
, 0, wParam
);
1933 case MM_GETMENUHANDLE
:
1935 return GetWindowLongPtrW(Wnd
, 0);
1938 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1944 /**********************************************************************
1945 * MENU_ParseResource
1947 * Parse a standard menu resource and add items to the menu.
1948 * Return a pointer to the end of the resource.
1950 * NOTE: flags is equivalent to the mtOption field
1952 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1961 flags
= GET_WORD(res
);
1963 /* remove MF_END flag before passing it to AppendMenu()! */
1964 end
= (flags
& MF_END
);
1965 if(end
) flags
^= MF_END
;
1967 res
+= sizeof(WORD
);
1968 if(!(flags
& MF_POPUP
))
1971 res
+= sizeof(WORD
);
1975 res
+= strlen(str
) + 1;
1977 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1978 if (flags
& MF_POPUP
)
1980 hSubMenu
= CreatePopupMenu();
1981 if(!hSubMenu
) return NULL
;
1982 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1985 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1987 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1989 else /* Not a popup */
1994 flags
= MF_SEPARATOR
;
1998 if (*(LPCWSTR
)str
== 0)
1999 flags
= MF_SEPARATOR
;
2002 if (flags
& MF_SEPARATOR
)
2004 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2005 flags
|= MF_GRAYED
| MF_DISABLED
;
2009 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2011 AppendMenuW(hMenu
, flags
, id
,
2012 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2019 /**********************************************************************
2020 * MENUEX_ParseResource
2022 * Parse an extended menu resource and add items to the menu.
2023 * Return a pointer to the end of the resource.
2025 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2031 mii
.cbSize
= sizeof(mii
);
2032 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
2033 mii
.fType
= GET_DWORD(res
);
2034 res
+= sizeof(DWORD
);
2035 mii
.fState
= GET_DWORD(res
);
2036 res
+= sizeof(DWORD
);
2037 mii
.wID
= GET_DWORD(res
);
2038 res
+= sizeof(DWORD
);
2039 resinfo
= GET_WORD(res
);
2040 res
+= sizeof(WORD
);
2041 /* Align the text on a word boundary. */
2042 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2043 mii
.dwTypeData
= (LPWSTR
) res
;
2044 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2045 /* Align the following fields on a dword boundary. */
2046 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2048 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2049 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2051 if (resinfo
& 1) { /* Pop-up? */
2052 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2053 res
+= sizeof(DWORD
);
2054 mii
.hSubMenu
= CreatePopupMenu();
2057 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2058 DestroyMenu(mii
.hSubMenu
);
2061 mii
.fMask
|= MIIM_SUBMENU
;
2062 mii
.fType
|= MF_POPUP
;
2063 mii
.wID
= (UINT
) mii
.hSubMenu
;
2065 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
2067 mii
.fType
|= MF_SEPARATOR
;
2069 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2070 } while (!(resinfo
& MF_END
));
2075 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2077 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2078 LRESULT Result
= (LRESULT
)hmenu
;
2079 MENUINFO menuinfo
= {0};
2080 MENUITEMINFOW info
= {0};
2082 // removing space for checkboxes from menu
2083 menuinfo
.cbSize
= sizeof(menuinfo
);
2084 menuinfo
.fMask
= MIM_STYLE
;
2085 GetMenuInfo(hmenu
, &menuinfo
);
2086 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2087 SetMenuInfo(hmenu
, &menuinfo
);
2089 // adding bitmaps to menu items
2090 info
.cbSize
= sizeof(info
);
2091 info
.fMask
|= MIIM_BITMAP
;
2092 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2093 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2094 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2095 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2096 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2097 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2098 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2099 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2101 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2108 NONCLIENTMETRICSW ncm
;
2110 /* get the menu font */
2111 if(!hMenuFont
|| !hMenuFontBold
)
2113 ncm
.cbSize
= sizeof(ncm
);
2114 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2116 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2120 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2121 if(hMenuFont
== NULL
)
2123 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2127 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2128 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2129 if(hMenuFontBold
== NULL
)
2131 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2132 DeleteObject(hMenuFont
);
2146 DeleteObject(hMenuFont
);
2152 DeleteObject(hMenuFontBold
);
2153 hMenuFontBold
= NULL
;
2157 /***********************************************************************
2158 * DrawMenuBarTemp (USER32.@)
2162 * called by W98SE desk.cpl Control Panel Applet
2164 * Not 100% sure about the param names, but close.
2169 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2171 ROSMENUINFO MenuInfo
;
2172 ROSMENUITEMINFO ItemInfo
;
2174 HFONT FontOld
= NULL
;
2175 BOOL flat_menu
= FALSE
;
2177 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2181 Menu
= GetMenu(Wnd
);
2189 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2191 return GetSystemMetrics(SM_CYMENU
);
2194 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2196 FontOld
= SelectObject(DC
, Font
);
2198 if (0 == MenuInfo
.Height
)
2200 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2203 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2205 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2207 SelectObject(DC
, GetStockObject(DC_PEN
));
2208 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2209 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
2210 LineTo(DC
, Rect
->right
, Rect
->bottom
);
2212 if (0 == MenuInfo
.MenuItemCount
)
2214 SelectObject(DC
, FontOld
);
2215 return GetSystemMetrics(SM_CYMENU
);
2218 MenuInitRosMenuItemInfo(&ItemInfo
);
2219 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2221 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2223 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2224 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2227 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2229 SelectObject(DC
, FontOld
);
2231 return MenuInfo
.Height
;
2234 /***********************************************************************
2237 * Display the sub-menu of the selected item of this menu.
2238 * Return the handle of the submenu, or menu if no submenu to display.
2240 static HMENU FASTCALL
2241 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2243 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2245 ROSMENUITEMINFO ItemInfo
;
2246 ROSMENUINFO SubMenuInfo
;
2250 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2252 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2254 return MenuInfo
->Self
;
2257 MenuInitRosMenuItemInfo(&ItemInfo
);
2258 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2260 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2261 return MenuInfo
->Self
;
2263 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2265 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2266 return MenuInfo
->Self
;
2269 /* message must be sent before using item,
2270 because nearly everything may be changed by the application ! */
2272 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2273 if (0 == (Flags
& TPM_NONOTIFY
))
2275 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2276 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2279 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2281 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2282 return MenuInfo
->Self
;
2284 Rect
= ItemInfo
.Rect
;
2286 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2287 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2289 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2291 Dc
= GetDC(MenuInfo
->Wnd
);
2295 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2298 SelectObject(Dc
, hMenuFont
);
2299 ItemInfo
.fMask
|= MIIM_STATE
;
2300 ItemInfo
.fState
|= MF_HILITE
;
2301 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2302 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2303 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2304 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2307 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2308 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2310 ItemInfo
.Rect
= Rect
;
2313 ItemInfo
.fMask
|= MIIM_STATE
;
2314 ItemInfo
.fState
|= MF_MOUSESELECT
;
2315 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2317 if (IS_SYSTEM_MENU(MenuInfo
))
2319 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2320 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2322 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2323 Rect
.top
= Rect
.bottom
;
2324 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2325 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2329 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2330 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2332 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2333 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2334 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2335 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2336 - GetSystemMetrics(SM_CYBORDER
);
2340 Rect
.left
+= ItemInfo
.Rect
.left
;
2341 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2342 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2343 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2347 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2348 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2349 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2351 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2354 Ret
= ItemInfo
.hSubMenu
;
2355 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2360 /**********************************************************************
2363 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2365 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2367 void MENU_EndMenu( HWND hwnd
)
2369 ROSMENUINFO MenuInfo
;
2371 if (top_popup_hmenu
)
2372 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2373 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2376 /***********************************************************************
2379 * Hide the sub-popup menus of this menu.
2381 static void FASTCALL
2382 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2383 BOOL SendMenuSelect
, UINT wFlags
)
2385 ROSMENUINFO SubMenuInfo
;
2386 ROSMENUITEMINFO ItemInfo
;
2388 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2390 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2392 MenuInitRosMenuItemInfo(&ItemInfo
);
2393 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2394 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2395 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2396 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2398 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2401 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2402 ItemInfo
.fMask
|= MIIM_STATE
;
2403 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2404 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2406 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2407 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2408 DestroyWindow(SubMenuInfo
.Wnd
);
2409 SubMenuInfo
.Wnd
= NULL
;
2410 MenuSetRosMenuInfo(&SubMenuInfo
);
2412 if (!(wFlags
& TPM_NONOTIFY
))
2413 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2414 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2419 /***********************************************************************
2420 * MenuSwitchTracking
2422 * Helper function for menu navigation routines.
2424 static void FASTCALL
2425 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2427 ROSMENUINFO TopMenuInfo
;
2429 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2431 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2432 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2433 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2435 /* both are top level menus (system and menu-bar) */
2436 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2437 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2438 Mt
->TopMenu
= PtMenuInfo
->Self
;
2442 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2445 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2448 /***********************************************************************
2449 * MenuExecFocusedItem
2451 * Execute a menu item (for instance when user pressed Enter).
2452 * Return the wID of the executed item. Otherwise, -1 indicating
2453 * that no menu item was executed, -2 if a popup is shown;
2454 * Have to receive the flags for the TrackPopupMenu options to avoid
2455 * sending unwanted message.
2459 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2461 ROSMENUITEMINFO ItemInfo
;
2464 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2466 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2471 MenuInitRosMenuItemInfo(&ItemInfo
);
2472 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2474 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2478 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2480 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2482 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2483 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2485 /* If TPM_RETURNCMD is set you return the id, but
2486 do not send a message to the owner */
2487 if (0 == (Flags
& TPM_RETURNCMD
))
2489 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2491 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2492 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2496 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2497 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2498 MenuInfo
->FocusedItem
,
2499 (LPARAM
)MenuInfo
->Self
);
2501 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2505 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2511 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2518 /***********************************************************************
2521 * Return TRUE if we can go on with menu tracking.
2523 static BOOL FASTCALL
2524 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2527 ROSMENUINFO MenuInfo
;
2528 ROSMENUITEMINFO Item
;
2530 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2534 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2538 if (IS_SYSTEM_MENU(&MenuInfo
))
2544 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2546 MenuInitRosMenuItemInfo(&Item
);
2547 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2549 MenuCleanupRosMenuItemInfo(&Item
);
2553 if (!(Item
.fType
& MF_SEPARATOR
) &&
2554 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2556 if (MenuInfo
.FocusedItem
!= Index
)
2558 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2561 /* If the popup menu is not already "popped" */
2562 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2564 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2568 MenuCleanupRosMenuItemInfo(&Item
);
2573 /* else the click was on the menu bar, finish the tracking */
2578 /***********************************************************************
2581 * Return the value of MenuExecFocusedItem if
2582 * the selected item was not a popup. Else open the popup.
2583 * A -1 return value indicates that we go on with menu tracking.
2587 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2590 ROSMENUINFO MenuInfo
;
2591 ROSMENUITEMINFO ItemInfo
;
2593 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2598 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2603 if (! IS_SYSTEM_MENU(&MenuInfo
))
2605 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2607 MenuInitRosMenuItemInfo(&ItemInfo
);
2608 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2609 MenuInfo
.FocusedItem
== Id
)
2611 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2613 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2614 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2615 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2617 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2619 /* If we are dealing with the top-level menu */
2620 /* and this is a click on an already "popped" item: */
2621 /* Stop the menu tracking and close the opened submenus */
2622 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2624 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2628 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2629 MenuInfo
.TimeToHide
= TRUE
;
2630 MenuSetRosMenuInfo(&MenuInfo
);
2636 /***********************************************************************
2639 * Walks menu chain trying to find a menu pt maps to.
2641 static HMENU FASTCALL
2642 MenuPtMenu(HMENU Menu
, POINT Pt
)
2644 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2645 ROSMENUINFO MenuInfo
;
2646 ROSMENUITEMINFO ItemInfo
;
2650 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2655 /* try subpopup first (if any) */
2656 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2658 MenuInitRosMenuItemInfo(&ItemInfo
);
2659 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2660 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2661 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2663 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2666 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2670 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2673 /* check the current window (avoiding WM_HITTEST) */
2674 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2675 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2677 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2682 else if (HTSYSMENU
== Ht
)
2684 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2686 else if (HTMENU
== Ht
)
2688 Ret
= GetMenu(MenuInfo
.Wnd
);
2694 /***********************************************************************
2697 * Return TRUE if we can go on with menu tracking.
2699 static BOOL FASTCALL
2700 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2703 ROSMENUINFO MenuInfo
;
2704 ROSMENUITEMINFO ItemInfo
;
2708 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2712 if (IS_SYSTEM_MENU(&MenuInfo
))
2718 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2723 Index
= NO_SELECTED_ITEM
;
2726 if (NO_SELECTED_ITEM
== Index
)
2728 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2729 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2731 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2735 else if (MenuInfo
.FocusedItem
!= Index
)
2737 MenuInitRosMenuItemInfo(&ItemInfo
);
2738 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2739 !(ItemInfo
.fType
& MF_SEPARATOR
))
2741 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2742 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2743 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2745 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2751 /***********************************************************************
2754 * Return the handle of the selected sub-popup menu (if any).
2756 static HMENU FASTCALL
2757 MenuGetSubPopup(HMENU Menu
)
2759 ROSMENUINFO MenuInfo
;
2760 ROSMENUITEMINFO ItemInfo
;
2762 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2763 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2768 MenuInitRosMenuItemInfo(&ItemInfo
);
2769 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2771 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2774 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2776 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2777 return ItemInfo
.hSubMenu
;
2780 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2784 /***********************************************************************
2787 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2789 static LRESULT FASTCALL
2790 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2792 ROSMENUINFO TopMenuInfo
;
2793 ROSMENUINFO MenuInfo
;
2795 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2797 return (LRESULT
) FALSE
;
2800 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2801 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2803 MDINEXTMENU NextMenu
;
2808 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2809 NextMenu
.hmenuNext
= NULL
;
2810 NextMenu
.hwndNext
= NULL
;
2811 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2813 TRACE("%p [%p] -> %p [%p]\n",
2814 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2816 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2818 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2819 NewWnd
= Mt
->OwnerWnd
;
2820 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2822 /* switch to the menu bar */
2824 if (0 != (Style
& WS_CHILD
)
2825 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2832 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2836 Id
= MenuInfo
.MenuItemCount
- 1;
2839 else if (0 != (Style
& WS_SYSMENU
))
2841 /* switch to the system menu */
2842 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2849 else /* application returned a new menu to switch to */
2851 NewMenu
= NextMenu
.hmenuNext
;
2852 NewWnd
= NextMenu
.hwndNext
;
2854 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2856 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2858 if (0 != (Style
& WS_SYSMENU
)
2859 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2861 /* get the real system menu */
2862 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2864 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2866 /* FIXME: Not sure what to do here;
2867 * perhaps try to track NewMenu as a popup? */
2869 WARN(" -- got confused.\n");
2879 if (NewMenu
!= Mt
->TopMenu
)
2881 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2883 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2885 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2889 if (NewWnd
!= Mt
->OwnerWnd
)
2891 Mt
->OwnerWnd
= NewWnd
;
2892 SetCapture(Mt
->OwnerWnd
);
2893 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2896 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2897 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2899 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2908 /***********************************************************************
2911 * The idea is not to show the popup if the next input message is
2912 * going to hide it anyway.
2914 static BOOL FASTCALL
2915 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2919 Msg
.hwnd
= Mt
->OwnerWnd
;
2921 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2922 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2927 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2928 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2930 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2931 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2932 if (WM_KEYDOWN
== Msg
.message
2933 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2935 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2942 /* failures go through this */
2943 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2948 /***********************************************************************
2951 * Handle a VK_ESCAPE key event in a menu.
2953 static BOOL FASTCALL
2954 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2956 BOOL EndMenu
= TRUE
;
2957 ROSMENUINFO MenuInfo
;
2958 HMENU MenuTmp
, MenuPrev
;
2960 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2962 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2963 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2965 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2967 /* close topmost popup */
2968 while (MenuTmp
!= Mt
->CurrentMenu
)
2971 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2974 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2976 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
2978 Mt
->CurrentMenu
= MenuPrev
;
2986 /***********************************************************************
2989 * Handle a VK_LEFT key event in a menu.
2991 static void FASTCALL
2992 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2994 ROSMENUINFO MenuInfo
;
2995 ROSMENUINFO TopMenuInfo
;
2996 ROSMENUINFO PrevMenuInfo
;
2997 HMENU MenuTmp
, MenuPrev
;
3000 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3002 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3007 /* Try to move 1 column left (if possible) */
3008 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3010 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3012 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3017 /* close topmost popup */
3018 while (MenuTmp
!= Mt
->CurrentMenu
)
3021 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3024 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3028 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3029 Mt
->CurrentMenu
= MenuPrev
;
3031 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3035 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3037 /* move menu bar selection if no more popups are left */
3039 if (! MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3041 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3044 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3046 /* A sublevel menu was displayed - display the next one
3047 * unless there is another displacement coming up */
3049 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3050 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3052 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3059 /***********************************************************************
3062 * Handle a VK_RIGHT key event in a menu.
3064 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3067 ROSMENUINFO MenuInfo
;
3068 ROSMENUINFO CurrentMenuInfo
;
3071 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3072 Mt
->CurrentMenu
, Mt
->TopMenu
);
3074 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3075 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3077 /* If already displaying a popup, try to display sub-popup */
3079 hmenutmp
= Mt
->CurrentMenu
;
3080 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3082 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3085 /* if subpopup was displayed then we are done */
3086 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3089 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3094 /* Check to see if there's another column */
3095 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3097 TRACE("Going to %d.\n", NextCol
);
3098 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3100 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3105 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3107 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3109 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3110 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3117 /* try to move to the next item */
3118 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3119 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3121 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3123 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3124 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3126 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3133 /***********************************************************************
3136 * Menu tracking code.
3138 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3139 HWND hwnd
, const RECT
*lprect
)
3142 ROSMENUINFO MenuInfo
;
3143 ROSMENUITEMINFO ItemInfo
;
3145 INT executedMenuId
= -1;
3147 BOOL enterIdleSent
= FALSE
;
3150 mt
.CurrentMenu
= hmenu
;
3156 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3157 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3158 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3162 WARN("Invalid menu handle %p\n", hmenu
);
3163 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3168 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3173 if (wFlags
& TPM_BUTTONDOWN
)
3175 /* Get the result in order to start the tracking or not */
3176 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3177 fEndMenu
= !fRemove
;
3180 SetCapture(mt
.OwnerWnd
);
3181 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, mt
.OwnerWnd
);
3183 ERR("MenuTrackMenu 1\n");
3186 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, VALIDATE_TYPE_MENU
);
3187 if (!menu
) /* sometimes happens if I do a window manager close */
3190 /* we have to keep the message in the queue until it's
3191 * clear that menu loop is not over yet. */
3195 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3197 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3198 /* remove the message from the queue */
3199 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3205 HWND win
= MenuInfo
.Flags
& MF_POPUP
? MenuInfo
.Wnd
: NULL
;
3206 enterIdleSent
= TRUE
;
3207 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3213 /* check if EndMenu() tried to cancel us, by posting this message */
3214 if (msg
.message
== WM_CANCELMODE
)
3216 /* we are now out of the loop */
3219 /* remove the message from the queue */
3220 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3222 /* break out of internal loop, ala ESCAPE */
3226 TranslateMessage( &msg
);
3229 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3230 enterIdleSent
=FALSE
;
3233 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3236 * Use the mouse coordinates in lParam instead of those in the MSG
3237 * struct to properly handle synthetic messages. They are already
3238 * in screen coordinates.
3240 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3241 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3243 /* Find a menu for this mouse event */
3244 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3248 /* no WM_NC... messages in captured state */
3250 case WM_RBUTTONDBLCLK
:
3251 case WM_RBUTTONDOWN
:
3252 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3254 case WM_LBUTTONDBLCLK
:
3255 case WM_LBUTTONDOWN
:
3256 /* If the message belongs to the menu, removes it from the queue */
3257 /* Else, end menu tracking */
3258 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3259 fEndMenu
= !fRemove
;
3263 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3266 /* Check if a menu was selected by the mouse */
3269 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3270 TRACE("executedMenuId %d\n", executedMenuId
);
3272 /* End the loop if executedMenuId is an item ID */
3273 /* or if the job was done (executedMenuId = 0). */
3274 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3276 /* No menu was selected by the mouse */
3277 /* if the function was called by TrackPopupMenu, continue
3278 with the menu tracking. If not, stop it */
3280 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3285 /* the selected menu item must be changed every time */
3286 /* the mouse moves. */
3289 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3291 } /* switch(msg.message) - mouse */
3293 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3295 fRemove
= TRUE
; /* Keyboard messages are always removed */
3309 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3311 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
3312 NO_SELECTED_ITEM
, FALSE
, 0 );
3313 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3314 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3319 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3320 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3322 if (!(MenuInfo
.Flags
& MF_POPUP
))
3324 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3325 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3327 else /* otherwise try to move selection */
3328 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3329 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3334 MenuKeyLeft( &mt
, wFlags
);
3338 MenuKeyRight( &mt
, wFlags
);
3342 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3348 hi
.cbSize
= sizeof(HELPINFO
);
3349 hi
.iContextType
= HELPINFO_MENUITEM
;
3350 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3352 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
)
3356 MenuInitRosMenuItemInfo(&ItemInfo
);
3357 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3358 MenuInfo
.FocusedItem
,
3361 hi
.iCtrlId
= ItemInfo
.wID
;
3367 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3370 hi
.hItemHandle
= hmenu
;
3371 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3372 hi
.MousePos
= msg
.pt
;
3373 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3380 break; /* WM_KEYDOWN */
3387 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3388 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3390 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3391 fEndMenu
= (executedMenuId
!= -2);
3395 /* Hack to avoid control chars. */
3396 /* We will find a better way real soon... */
3397 if (msg
.wParam
< 32) break;
3399 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3400 LOWORD(msg
.wParam
), FALSE
);
3401 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3402 else if (pos
== (UINT
)-1) MessageBeep(0);
3405 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3407 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3408 fEndMenu
= (executedMenuId
!= -2);
3412 } /* switch(msg.message) - kbd */
3416 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3417 DispatchMessageW( &msg
);
3421 if (!fEndMenu
) fRemove
= TRUE
;
3423 /* finally remove message from the queue */
3425 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3426 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3427 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3429 ERR("MenuTrackMenu 2\n");
3431 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3432 SetCapture(NULL
); /* release the capture */
3434 /* If dropdown is still painted and the close box is clicked on
3435 then the menu will be destroyed as part of the DispatchMessage above.
3436 This will then invalidate the menu handle in mt.hTopMenu. We should
3437 check for this first. */
3438 if( IsMenu( mt
.TopMenu
) )
3440 if (IsWindow(mt
.OwnerWnd
))
3442 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3444 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3446 if (MenuInfo
.Flags
& MF_POPUP
)
3448 DestroyWindow(MenuInfo
.Wnd
);
3449 MenuInfo
.Wnd
= NULL
;
3451 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3452 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3453 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3456 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3459 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3462 /* Reset the variable for hiding menu */
3463 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3465 MenuInfo
.TimeToHide
= FALSE
;
3466 MenuSetRosMenuInfo(&MenuInfo
);
3470 /* The return value is only used by TrackPopupMenu */
3471 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3472 if (executedMenuId
== -1) executedMenuId
= 0;
3473 return executedMenuId
;
3476 /***********************************************************************
3479 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3481 ROSMENUINFO MenuInfo
;
3483 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3487 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3488 if (!(wFlags
& TPM_NONOTIFY
))
3489 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3491 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3493 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
3495 if (!(wFlags
& TPM_NONOTIFY
))
3497 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3498 /* If an app changed/recreated menu bar entries in WM_INITMENU
3499 * menu sizes will be recalculated once the menu created/shown.
3502 if (!MenuInfo
.Height
)
3504 /* app changed/recreated menu bar entries in WM_INITMENU
3505 Recalculate menu sizes else clicks will not work */
3506 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3507 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3512 /* This makes the menus of applications built with Delphi work.
3513 * It also enables menus to be displayed in more than one window,
3514 * but there are some bugs left that need to be fixed in this case.
3516 if(MenuInfo
.Self
== hMenu
)
3518 MenuInfo
.Wnd
= hWnd
;
3519 MenuSetRosMenuInfo(&MenuInfo
);
3524 /***********************************************************************
3527 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
)
3529 TRACE("hwnd=%p\n", hWnd
);
3531 SendMessageW( hWnd
, WM_EXITMENULOOP
, 0, 0 );
3534 top_popup_hmenu
= NULL
;
3538 /***********************************************************************
3539 * MenuTrackMouseMenuBar
3541 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3543 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3545 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3546 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3548 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3552 /* map point to parent client coordinates */
3553 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3554 if (Parent
!= GetDesktopWindow())
3556 ScreenToClient(Parent
, &pt
);
3559 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3560 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3561 MenuExitTracking(hWnd
);
3566 /***********************************************************************
3567 * MenuTrackKbdMenuBar
3569 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3571 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3573 UINT uItem
= NO_SELECTED_ITEM
;
3575 ROSMENUINFO MenuInfo
;
3576 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3578 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3580 /* find window that has a menu */
3582 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3583 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3584 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3586 /* check if we have to track a system menu */
3588 hTrackMenu
= GetMenu( hwnd
);
3589 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3591 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3592 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3594 wParam
|= HTSYSMENU
; /* prevent item lookup */
3597 if (!IsMenu( hTrackMenu
)) return;
3599 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3601 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3606 if( wChar
&& wChar
!= ' ' )
3608 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3609 if ( uItem
>= (UINT
)(-2) )
3611 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3612 /* schedule end of menu tracking */
3613 wFlags
|= TF_ENDMENU
;
3618 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3620 if (wParam
& HTSYSMENU
)
3622 /* prevent sysmenu activation for managed windows on Alt down/up */
3623 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3624 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3628 if( uItem
== NO_SELECTED_ITEM
)
3629 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3631 PostMessageW( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3635 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3636 MenuExitTracking( hwnd
);
3640 /**********************************************************************
3641 * TrackPopupMenuEx (USER32.@)
3643 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
3644 HWND Wnd
, LPTPMPARAMS Tpm
)
3650 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3654 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
3656 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3657 if (!(Flags
& TPM_NONOTIFY
))
3658 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
3660 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
3661 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
3662 Tpm
? &Tpm
->rcExclude
: NULL
);
3663 MenuExitTracking(Wnd
);
3667 /**********************************************************************
3668 * TrackPopupMenu (USER32.@)
3670 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
3671 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
3673 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
3678 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3679 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3681 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3683 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3684 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3685 * MFT_STRING is replaced by MIIM_STRING.
3686 * (So, I guess we should use MIIM_STRING only for strings?)
3688 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3690 * Based on wine, SetMenuItemInfo_common:
3691 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3692 * it will result in a error.
3693 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3694 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3701 LPMENUITEMINFOW mii
,
3708 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3710 if(Flags
& MF_BITMAP
)
3712 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3713 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3715 if (Flags
& MF_HELP
)
3717 /* increase ident */
3718 mii
->fType
|= MF_HELP
;
3721 else if(Flags
& MF_OWNERDRAW
)
3723 mii
->fType
|= MFT_OWNERDRAW
;
3724 mii
->fMask
|= MIIM_DATA
;
3725 mii
->dwItemData
= (DWORD
) NewItem
;
3727 else if (Flags
& MF_SEPARATOR
)
3729 mii
->fType
|= MFT_SEPARATOR
;
3730 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3731 Flags
|= MF_GRAYED
|MF_DISABLED
;
3733 else /* Default action MF_STRING. */
3735 /* Item beginning with a backspace is a help item */
3736 if (NewItem
!= NULL
)
3740 if (*NewItem
== '\b')
3742 mii
->fType
|= MF_HELP
;
3748 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3749 if (*NewItemA
== '\b')
3751 mii
->fType
|= MF_HELP
;
3753 NewItem
= (LPCWSTR
) NewItemA
;
3757 if (Flags
& MF_HELP
)
3758 mii
->fType
|= MF_HELP
;
3759 mii
->fMask
|= MIIM_STRING
;
3760 mii
->fType
|= MFT_STRING
; /* Zero */
3761 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3763 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3765 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3769 mii
->fType
|= MFT_SEPARATOR
;
3770 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3771 Flags
|= MF_GRAYED
|MF_DISABLED
;
3775 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3777 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3780 if(Flags
& MF_MENUBREAK
)
3782 mii
->fType
|= MFT_MENUBREAK
;
3784 else if(Flags
& MF_MENUBARBREAK
)
3786 mii
->fType
|= MFT_MENUBARBREAK
;
3789 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3791 if (Flags
& MF_GRAYED
)
3792 mii
->fState
|= MF_GRAYED
;
3794 if (Flags
& MF_DISABLED
)
3795 mii
->fState
|= MF_DISABLED
;
3797 mii
->fMask
|= MIIM_STATE
;
3799 else if (Flags
& MF_HILITE
)
3801 mii
->fState
|= MF_HILITE
;
3802 mii
->fMask
|= MIIM_STATE
;
3804 else /* default state */
3806 mii
->fState
|= MFS_ENABLED
;
3807 mii
->fMask
|= MIIM_STATE
;
3810 if(Flags
& MF_POPUP
)
3812 mii
->fType
|= MF_POPUP
;
3813 mii
->fMask
|= MIIM_SUBMENU
;
3814 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3818 mii
->fMask
|= MIIM_ID
;
3819 mii
->wID
= (UINT
)IDNewItem
;
3825 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3827 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3830 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3832 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3833 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3834 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3835 (LPCWSTR
)&Common
->MenuName
);
3837 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3841 /* FUNCTIONS *****************************************************************/
3844 MenuIsStringItem(ULONG TypeData)
3846 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3854 AppendMenuA(HMENU hMenu
,
3856 UINT_PTR uIDNewItem
,
3859 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3868 AppendMenuW(HMENU hMenu
,
3870 UINT_PTR uIDNewItem
,
3873 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3882 CheckMenuItem(HMENU hmenu
,
3886 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3891 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3894 PROSMENUITEMINFO Items
= NULL
;
3895 UINT cChecked
, cUnchecked
;
3899 if(idFirst
> idLast
)
3902 ItemCount
= GetMenuItemCount(hMenu
);
3904 //mi.cbSize = sizeof(ROSMENUINFO);
3905 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3908 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3910 ERR("MenuGetAllRosMenuItemInfo failed\n");
3914 cChecked
= cUnchecked
= 0;
3916 for (i
= 0 ; i
< ItemCount
; i
++)
3919 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3920 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3922 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3924 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3927 if (uFlags
& MF_BYPOSITION
)
3929 if (i
< idFirst
|| i
> idLast
)
3944 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3947 if (Items
[i
].wID
== idCheck
)
3961 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
3964 Items
[i
].fType
|= MFT_RADIOCHECK
;
3965 Items
[i
].fState
|= MFS_CHECKED
;
3969 Items
[i
].fState
&= ~MFS_CHECKED
;
3972 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
3974 ERR("MenuSetRosMenuItemInfo failed\n");
3979 HeapFree(GetProcessHeap(), 0, Items
);
3981 *pChecked
+= cChecked
;
3982 *pUnchecked
+= cUnchecked
;
3984 if (cChecked
|| cUnchecked
)
3994 CheckMenuRadioItem(HMENU hmenu
,
4001 UINT cUnchecked
= 0;
4002 UINT cMenuChanged
= 0;
4004 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4007 if (cMenuChanged
> 1)
4014 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4017 return (cChecked
!= 0);
4028 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4036 CreatePopupMenu(VOID
)
4039 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4047 DrawMenuBar(HWND hWnd
)
4049 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4050 ROSMENUINFO MenuInfo
;
4052 hMenu
= GetMenu(hWnd
);
4055 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4056 MenuInfo
.Height
= 0; // make sure to recalc size
4057 MenuSetRosMenuInfo(&MenuInfo
);
4058 /* The wine method doesn't work and I suspect it's more effort
4059 then hackfix solution
4060 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4061 SWP_NOZORDER | SWP_FRAMECHANGED );
4064 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4072 EnableMenuItem(HMENU hMenu
,
4076 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4086 guii
.cbSize
= sizeof(GUITHREADINFO
);
4087 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4091 guii
.hwndMenuOwner
!= top_popup
)
4093 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4097 /* if we are in the menu code, and it is active */
4098 if (!fEndMenu
&& top_popup
)
4100 /* terminate the menu handling code */
4103 /* needs to be posted to wakeup the internal menu handler */
4104 /* which will now terminate the menu, in the event that */
4105 /* the main window was minimized, or lost focus, so we */
4106 /* don't end up with an orphaned menu */
4107 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4112 // So this one maybe one day it will be a callback!
4113 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4116 ROSMENUINFO MenuInfo
;
4117 ROSMENUITEMINFO mii
;
4118 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4121 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4124 if (!NtUserMenuItemInfo(hMenu
, wItemID
, wHilite
, &mii
, FALSE
)) return FALSE
;
4125 if (!NtUserMenuInfo(hMenu
, &MenuInfo
, FALSE
)) return FALSE
;
4126 if (MenuInfo
.FocusedItem
== wItemID
) return TRUE
;
4127 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4128 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4138 PWND Wnd
= ValidateHwnd(hWnd
);
4143 return (HMENU
)Wnd
->IDMenu
;
4151 GetMenuCheckMarkDimensions(VOID
)
4153 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4154 GetSystemMetrics(SM_CYMENUCHECK
)));
4162 GetMenuDefaultItem(HMENU hMenu
,
4166 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4174 GetMenuInfo(HMENU hmenu
,
4180 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4183 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4184 mi
.cbSize
= sizeof(MENUINFO
);
4185 mi
.fMask
= lpcmi
->fMask
;
4187 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4189 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4198 GetMenuItemCount(HMENU Menu
)
4200 ROSMENUINFO MenuInfo
;
4202 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4210 GetMenuItemID(HMENU hMenu
,
4213 ROSMENUITEMINFO mii
;
4215 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4216 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4218 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4223 if (NULL
!= mii
.hSubMenu
)
4244 LPMENUITEMINFOA mii
)
4250 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4251 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4253 SetLastError(ERROR_INVALID_PARAMETER
);
4257 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4259 /* No text requested, just pass on */
4260 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4263 AnsiBuffer
= mii
->dwTypeData
;
4264 Count
= miiW
.cch
= mii
->cch
;
4265 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4266 miiW
.dwTypeData
= 0;
4270 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4271 miiW
.cch
* sizeof(WCHAR
));
4272 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4273 miiW
.dwTypeData
[0] = 0;
4276 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4278 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4282 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4284 if (!AnsiBuffer
|| !Count
)
4286 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4287 mii
->dwTypeData
= AnsiBuffer
;
4288 mii
->cch
= miiW
.cch
;
4292 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4296 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4300 if (Count
> miiW
.cch
)
4302 AnsiBuffer
[miiW
.cch
] = 0;
4304 mii
->cch
= mii
->cch
;
4312 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4313 mii
->dwTypeData
= AnsiBuffer
;
4327 LPMENUITEMINFOW mii
)
4333 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4334 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4336 SetLastError(ERROR_INVALID_PARAMETER
);
4340 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4342 /* No text requested, just pass on */
4343 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4346 String
= mii
->dwTypeData
;
4348 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4349 miiW
.dwTypeData
= 0;
4353 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4354 miiW
.cch
* sizeof(WCHAR
));
4355 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4356 miiW
.dwTypeData
[0] = 0;
4359 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4361 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4365 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4367 if (!String
|| !Count
)
4369 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4370 mii
->dwTypeData
= String
; // may not be zero.
4371 mii
->cch
= miiW
.cch
;
4375 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4377 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4380 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4381 mii
->dwTypeData
= String
;
4382 mii
->cch
= strlenW(String
);
4397 ROSMENUINFO MenuInfo
;
4398 ROSMENUITEMINFO mii
;
4399 memset( &mii
, 0, sizeof(mii
) );
4400 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4401 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4404 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4409 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4413 nSubItems
= MenuInfo
.MenuItemCount
;
4415 /* FIXME - ported from wine, does that work (0xff)? */
4416 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4417 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4419 return (UINT
)-1; /* Invalid submenu */
4422 /* FIXME - ported from wine, does that work? */
4423 return (mii
.fType
| mii
.fState
);
4443 memset( &mii
, 0, sizeof(mii
) );
4444 mii
.dwTypeData
= lpString
;
4445 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4446 mii
.fType
= MFT_STRING
;
4447 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4448 mii
.cch
= nMaxCount
;
4450 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4470 memset( &miiW
, 0, sizeof(miiW
) );
4471 miiW
.dwTypeData
= lpString
;
4472 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4473 miiW
.fType
= MFT_STRING
;
4474 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4475 miiW
.cch
= nMaxCount
;
4477 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4495 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4496 mi
.fMask
= MIIM_SUBMENU
;
4498 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4500 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4517 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4519 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4532 UINT_PTR uIDNewItem
,
4536 memset( &mii
, 0, sizeof(mii
) );
4537 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4538 mii
.fMask
= MIIM_FTYPE
;
4540 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4543 (LPCWSTR
) lpNewItem
,
4546 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4560 LPCMENUITEMINFOA lpmii
)
4563 UNICODE_STRING MenuText
;
4565 BOOL CleanHeap
= FALSE
;
4568 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4569 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4571 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4573 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4575 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4578 /* copy the text string */
4579 if (((mi
.fMask
& MIIM_STRING
) ||
4580 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4581 && mi
.dwTypeData
!= NULL
)
4583 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4584 if (!NT_SUCCESS (Status
))
4586 SetLastError (RtlNtStatusToDosError(Status
));
4589 mi
.dwTypeData
= MenuText
.Buffer
;
4590 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4593 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4595 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4610 LPCMENUITEMINFOW lpmii
)
4613 UNICODE_STRING MenuText
;
4616 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4617 if a bad user passes bad data, we crash his process instead of the
4620 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4621 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4623 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4625 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4627 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4630 /* copy the text string */
4631 if (((mi
.fMask
& MIIM_STRING
) ||
4632 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4633 && mi
.dwTypeData
!= NULL
)
4635 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4636 mi
.dwTypeData
= MenuText
.Buffer
;
4637 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4639 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4654 UINT_PTR uIDNewItem
,
4658 memset( &mii
, 0, sizeof(mii
) );
4659 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4660 mii
.fMask
= MIIM_FTYPE
;
4662 MenuSetItemData( &mii
,
4668 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4680 if (ValidateHandle(Menu
, VALIDATE_TYPE_MENU
)) return TRUE
;
4689 LoadMenuA(HINSTANCE hInstance
,
4692 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4693 if (Resource
== NULL
)
4697 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4705 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4707 return(LoadMenuIndirectW(lpMenuTemplate
));
4715 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4718 WORD version
, offset
;
4719 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4721 version
= GET_WORD(p
);
4726 case 0: /* standard format is version of 0 */
4727 offset
= GET_WORD(p
);
4728 p
+= sizeof(WORD
) + offset
;
4729 if (!(hMenu
= CreateMenu())) return 0;
4730 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4736 case 1: /* extended format is version of 1 */
4737 offset
= GET_WORD(p
);
4738 p
+= sizeof(WORD
) + offset
;
4739 if (!(hMenu
= CreateMenu())) return 0;
4740 if (!MENUEX_ParseResource(p
, hMenu
))
4742 DestroyMenu( hMenu
);
4747 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4757 LoadMenuW(HINSTANCE hInstance
,
4760 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4761 if (Resource
== NULL
)
4765 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4779 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4792 UINT_PTR uIDNewItem
,
4796 ROSMENUITEMINFO rmii
;
4798 memset( &mii
, 0, sizeof(mii
) );
4799 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4800 mii
.fMask
= MIIM_FTYPE
;
4802 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4806 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4808 MenuInitRosMenuItemInfo( &rmii
);
4810 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4812 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4813 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4815 MenuCleanupRosMenuItemInfo( &rmii
);
4817 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4820 (LPCWSTR
) lpNewItem
,
4823 return SetMenuItemInfoA( hMnu
,
4825 (BOOL
)(MF_BYPOSITION
& uFlags
),
4839 UINT_PTR uIDNewItem
,
4843 ROSMENUITEMINFO rmii
;
4845 memset ( &mii
, 0, sizeof(mii
) );
4846 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4847 mii
.fMask
= MIIM_FTYPE
;
4849 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4851 mi
.Height
= 0; // Force size recalculation.
4853 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4855 MenuInitRosMenuItemInfo( &rmii
);
4857 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4859 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4860 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4862 MenuCleanupRosMenuItemInfo( &rmii
);
4864 /* Init new data for this menu item */
4865 MenuSetItemData( &mii
,
4871 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4872 return SetMenuItemInfoW( hMnu
,
4874 (BOOL
)(MF_BYPOSITION
& uFlags
),
4886 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4902 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4904 SetLastError(ERROR_INVALID_PARAMETER
);
4908 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4909 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4922 HBITMAP hBitmapUnchecked
,
4923 HBITMAP hBitmapChecked
)
4925 ROSMENUITEMINFO uItem
;
4926 memset ( &uItem
, 0, sizeof(uItem
) );
4927 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4929 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4930 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4932 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4934 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4936 else /* Install new bitmaps */
4938 uItem
.hbmpChecked
= hBitmapChecked
;
4939 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4940 uItem
.fState
|= MF_USECHECKBITMAPS
;
4942 return NtUserMenuItemInfo(hMenu
, uPosition
,
4943 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4956 LPCMENUITEMINFOA lpmii
)
4958 MENUITEMINFOW MenuItemInfoW
;
4959 UNICODE_STRING UnicodeString
;
4961 ULONG Result
= FALSE
;
4963 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4965 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4967 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4968 MenuItemInfoW
.hbmpItem
= NULL
;
4971 * MIIM_STRING == good
4972 * MIIM_TYPE & MFT_STRING == good
4973 * MIIM_STRING & MFT_STRING == good
4974 * MIIM_STRING & MFT_OWNERSRAW == good
4976 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
4977 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
4978 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
4979 && MenuItemInfoW
.dwTypeData
!= NULL
)
4981 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
4982 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
4983 (LPSTR
)MenuItemInfoW
.dwTypeData
);
4984 if (!NT_SUCCESS (Status
))
4986 SetLastError (RtlNtStatusToDosError(Status
));
4989 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
4990 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4994 UnicodeString
.Buffer
= NULL
;
4997 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
4998 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5000 if (UnicodeString
.Buffer
!= NULL
)
5002 RtlFreeUnicodeString(&UnicodeString
);
5018 LPCMENUITEMINFOW lpmii
)
5020 MENUITEMINFOW MenuItemInfoW
;
5023 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5025 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5027 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5028 MenuItemInfoW
.hbmpItem
= NULL
;
5031 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5032 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5033 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5034 && MenuItemInfoW
.dwTypeData
!= NULL
)
5036 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5038 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5039 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5055 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5060 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5063 return NtUserSetSystemMenu(hwnd
, hMenu
);
5067 // Example for the Win32/User32 rewrite.
5068 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5082 return NtUserTrackPopupMenuEx( Menu
,
5087 NULL
); // LPTPMPARAMS is null
5096 GetMenuContextHelpId(HMENU hmenu
)
5099 mi
.cbSize
= sizeof(ROSMENUINFO
);
5100 mi
.fMask
= MIM_HELPID
;
5102 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5104 return mi
.dwContextHelpID
;
5125 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5128 Result
= (ULONG_PTR
)lResult
;
5133 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5153 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5156 Result
= (ULONG_PTR
)lResult
;
5161 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5172 LPCWSTR lpszNewItem
,
5177 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5178 for MF_DELETE. We should check the parameters for all others
5179 MF_* actions also (anybody got a doc on ChangeMenu?).
5182 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5185 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5188 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5191 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5194 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5195 flags
&~ MF_REMOVE
);
5197 default : /* MF_INSERT */
5198 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5215 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5216 for MF_DELETE. We should check the parameters for all others
5217 MF_* actions also (anybody got a doc on ChangeMenu?).
5220 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5223 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5226 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5229 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5232 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5233 flags
&~ MF_REMOVE
);
5235 default : /* MF_INSERT */
5236 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);