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