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 */
39 /* top and bottom margins for popup menus */
40 #define MENU_TOP_MARGIN 3
41 #define MENU_BOTTOM_MARGIN 2
43 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
45 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
47 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
48 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
49 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
51 #define IS_SYSTEM_MENU(MenuInfo) \
52 (0 == ((MenuInfo)->Flags & MNF_POPUP) && 0 != ((MenuInfo)->Flags & MNF_SYSDESKMN))
54 #define IS_SYSTEM_POPUP(MenuInfo) \
55 (0 != ((MenuInfo)->Flags & MNF_POPUP) && 0 != ((MenuInfo)->Flags & MNF_SYSDESKMN))
57 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
59 /* Use global popup window because there's no way 2 menus can
60 * be tracked at the same time. */
61 static HWND top_popup
;
62 static HMENU top_popup_hmenu
;
64 /* Flag set by EndMenu() to force an exit from menu tracking */
65 static BOOL fEndMenu
= FALSE
;
67 #define MENU_ITEM_HBMP_SPACE (5)
68 #define MENU_BAR_ITEMS_SPACE (12)
69 #define SEPARATOR_HEIGHT (5)
70 #define MENU_TAB_SPACE (8)
75 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
76 HMENU TopMenu
; /* initial menu */
77 HWND OwnerWnd
; /* where notifications are sent */
82 /*********************************************************************
83 * PopupMenu class descriptor
85 const struct builtin_class_descr POPUPMENU_builtin_class
=
88 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
89 (WNDPROC
) NULL
, /* FIXME - procA */
90 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
91 sizeof(MENUINFO
*), /* extra */
92 (LPCWSTR
) IDC_ARROW
, /* cursor */
93 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
97 #define GET_WORD(ptr) (*(WORD *)(ptr))
100 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
103 HFONT hMenuFont
= NULL
;
104 HFONT hMenuFontBold
= NULL
;
106 /* Dimension of the menu bitmaps */
107 static HBITMAP BmpSysMenu
= NULL
;
109 static SIZE MenuCharSize
;
111 /***********************************************************************
114 * Get full information about menu
117 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
119 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
120 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
122 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
125 /***********************************************************************
128 * Set full information about menu
131 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
133 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
134 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
136 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
139 /***********************************************************************
140 * MenuInitRosMenuItemInfo
142 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
145 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
147 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
148 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
151 /***********************************************************************
152 * MenuGetRosMenuItemInfo
154 * Get full information about a menu item
157 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
159 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
161 if (ItemInfo
->dwTypeData
!= NULL
)
163 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
167 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
168 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
169 ItemInfo
->dwTypeData
= NULL
;
171 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
177 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
180 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
181 ItemInfo
->cch
* sizeof(WCHAR
));
182 if (NULL
== ItemInfo
->dwTypeData
)
187 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
192 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
194 ItemInfo
->fMask
= Save_Mask
;
198 /***********************************************************************
199 * MenuSetRosMenuItemInfo
201 * Set selected information about a menu item, need to set the mask bits.
204 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
208 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
209 ItemInfo
->dwTypeData
!= NULL
)
211 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
213 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
218 /***********************************************************************
219 * MenuCleanupRosMenuItemInfo
221 * Cleanup after use of MenuGet/SetRosMenuItemInfo
224 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
226 if (ItemInfo
->dwTypeData
!= NULL
)
228 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
229 ItemInfo
->dwTypeData
= NULL
;
233 /***********************************************************************
234 * MenuGetAllRosMenuItemInfo
236 * Get full information about all menu items
239 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
243 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
244 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
248 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
249 if (NULL
== *ItemInfo
)
254 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
257 /***********************************************************************
258 * MenuCleanupAllRosMenuItemInfo
260 * Cleanup after use of MenuGetAllRosMenuItemInfo
263 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
265 HeapFree(GetProcessHeap(), 0, ItemInfo
);
268 /***********************************************************************
269 * MenuInitSysMenuPopup
271 * Grey the appropriate items in System menu.
273 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
281 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
282 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
283 gray
= ((style
& WS_MAXIMIZE
) != 0);
284 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
285 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
286 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
287 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
288 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
289 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
290 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
291 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
293 /* The menu item must keep its state if it's disabled */
295 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
297 /* Set default menu item */
298 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
299 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
300 else DefItem
= SC_CLOSE
;
302 mii
.cbSize
= sizeof(MENUITEMINFOW
);
303 mii
.fMask
|= MIIM_STATE
;
304 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
305 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
307 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
310 /******************************************************************************
312 * UINT MenuGetStartOfNextColumn(
313 * PROSMENUINFO MenuInfo)
315 *****************************************************************************/
316 static UINT
MenuGetStartOfNextColumn(
317 PROSMENUINFO MenuInfo
)
319 PROSMENUITEMINFO MenuItems
;
322 i
= MenuInfo
->FocusedItem
;
323 if ( i
== NO_SELECTED_ITEM
)
326 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
327 return NO_SELECTED_ITEM
;
329 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
330 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
333 return NO_SELECTED_ITEM
;
336 /******************************************************************************
338 * UINT MenuGetStartOfPrevColumn(
339 * PROSMENUINFO MenuInfo)
341 *****************************************************************************/
343 static UINT FASTCALL
MenuGetStartOfPrevColumn(
344 PROSMENUINFO MenuInfo
)
346 PROSMENUITEMINFO MenuItems
;
349 if (!MenuInfo
->FocusedItem
|| MenuInfo
->FocusedItem
== NO_SELECTED_ITEM
)
350 return NO_SELECTED_ITEM
;
352 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
353 return NO_SELECTED_ITEM
;
355 /* Find the start of the column */
356 for (i
= MenuInfo
->FocusedItem
;
357 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
365 MenuCleanupAllRosMenuItemInfo(MenuItems
);
366 return NO_SELECTED_ITEM
;
369 for (--i
; 0 != i
; --i
)
370 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
373 MenuCleanupAllRosMenuItemInfo(MenuItems
);
374 TRACE("ret %d.\n", i
);
379 /***********************************************************************
382 * Find a Sub menu. Return the position of the submenu, and modifies
383 * *hmenu in case it is found in another sub-menu.
384 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
386 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
390 ROSMENUITEMINFO item
;
391 if (((*hmenu
)==(HMENU
)0xffff) ||
392 (!MenuGetRosMenuInfo(&menu
, *hmenu
)))
393 return NO_SELECTED_ITEM
;
395 MenuInitRosMenuItemInfo(&item
);
396 for (i
= 0; i
< menu
.MenuItemCount
; i
++) {
397 if (! MenuGetRosMenuItemInfo(menu
.Self
, i
, &item
))
399 MenuCleanupRosMenuItemInfo(&item
);
400 return NO_SELECTED_ITEM
;
402 if (!(item
.hSubMenu
)) continue;
403 if (item
.hSubMenu
== hSubTarget
) {
404 MenuCleanupRosMenuItemInfo(&item
);
408 HMENU hsubmenu
= item
.hSubMenu
;
409 UINT pos
= MenuFindSubMenu(&hsubmenu
, hSubTarget
);
410 if (pos
!= NO_SELECTED_ITEM
) {
416 MenuCleanupRosMenuItemInfo(&item
);
417 return NO_SELECTED_ITEM
;
420 /***********************************************************************
423 * Load the arrow bitmap. We can't do this from MenuInit since user32
424 * can also be used (and thus initialized) from text-mode.
427 MenuLoadBitmaps(VOID
)
429 /* Load system buttons bitmaps */
430 if (NULL
== BmpSysMenu
)
432 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
436 /***********************************************************************
439 * Draws popup magic glyphs (can be found in system menu).
442 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
445 HFONT hFont
, hOldFont
;
451 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
454 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
457 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
460 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
464 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
467 ZeroMemory(&lf
, sizeof(LOGFONTW
));
468 InflateRect(r
, -2, -2);
469 lf
.lfHeight
= r
->bottom
- r
->top
;
471 lf
.lfWeight
= FW_NORMAL
;
472 lf
.lfCharSet
= DEFAULT_CHARSET
;
473 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
474 hFont
= CreateFontIndirect(&lf
);
475 /* save font and text color */
476 hOldFont
= SelectObject(dc
, hFont
);
477 clrsave
= GetTextColor(dc
);
478 bkmode
= GetBkMode(dc
);
479 /* set color and drawing mode */
480 SetBkMode(dc
, TRANSPARENT
);
486 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
487 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
490 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
491 /* draw selected symbol */
492 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
493 /* restore previous settings */
494 SetTextColor(dc
, clrsave
);
495 SelectObject(dc
, hOldFont
);
496 SetBkMode(dc
, bkmode
);
500 /***********************************************************************
503 * Find the menu item selected by a key press.
504 * Return item id, -1 if none, -2 if we should close the menu.
506 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
507 WCHAR Key
, BOOL ForceMenuChar
)
509 ROSMENUINFO SysMenuInfo
;
510 PROSMENUITEMINFO Items
, ItemInfo
;
515 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
517 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
519 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
521 MenuInfo
= &SysMenuInfo
;
529 if (NULL
!= MenuInfo
)
531 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
535 if ( !ForceMenuChar
)
538 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
540 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
542 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
545 p
= strchrW (p
+ 2, '&');
547 while (p
!= NULL
&& p
[1] == '&');
548 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
553 Flags
|= MenuInfo
->Flags
& MNF_POPUP
? MF_POPUP
: 0;
554 Flags
|= MenuInfo
->Flags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0;
556 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
557 MAKEWPARAM(Key
, Flags
), (LPARAM
) MenuInfo
->Self
);
558 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
559 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
564 /***********************************************************************
565 * MenuGetBitmapItemSize
567 * Get the size of a bitmap item.
569 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
572 HBITMAP bmp
= lpitem
->hbmpItem
;
574 size
->cx
= size
->cy
= 0;
576 /* check if there is a magic menu item associated with this item */
577 if (IS_MAGIC_BITMAP(bmp
))
579 switch((INT_PTR
) bmp
)
581 case (INT_PTR
)HBMMENU_CALLBACK
:
583 MEASUREITEMSTRUCT measItem
;
584 measItem
.CtlType
= ODT_MENU
;
586 measItem
.itemID
= lpitem
->wID
;
587 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
588 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
589 measItem
.itemData
= lpitem
->dwItemData
;
590 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
591 size
->cx
= measItem
.itemWidth
;
592 size
->cy
= measItem
.itemHeight
;
597 case (INT_PTR
) HBMMENU_SYSTEM
:
598 if (0 != lpitem
->dwItemData
)
600 bmp
= (HBITMAP
) lpitem
->dwItemData
;
604 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
605 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
606 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
607 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
608 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
609 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
610 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
611 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
612 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
613 /* FIXME: Why we need to subtract these magic values? */
614 /* to make them smaller than the menu bar? */
615 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
616 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
621 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
623 size
->cx
= bm
.bmWidth
;
624 size
->cy
= bm
.bmHeight
;
628 /***********************************************************************
631 * Draw a bitmap item.
633 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
634 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
640 int w
= rect
->right
- rect
->left
;
641 int h
= rect
->bottom
- rect
->top
;
644 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
647 /* Check if there is a magic menu item associated with this item */
648 if (IS_MAGIC_BITMAP(hbmToDraw
))
654 switch ((INT_PTR
)hbmToDraw
)
656 case (INT_PTR
)HBMMENU_SYSTEM
:
657 if (lpitem
->dwTypeData
)
659 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
660 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
664 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
666 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
667 /* only use right half of the bitmap */
668 bmp_xoffset
= bm
.bmWidth
/ 2;
669 bm
.bmWidth
-= bmp_xoffset
;
672 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
673 flags
= DFCS_CAPTIONRESTORE
;
675 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
677 flags
= DFCS_CAPTIONMIN
;
679 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
681 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
683 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
684 flags
= DFCS_CAPTIONCLOSE
;
686 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
687 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
689 case (INT_PTR
)HBMMENU_CALLBACK
:
691 DRAWITEMSTRUCT drawItem
;
693 drawItem
.CtlType
= ODT_MENU
;
695 drawItem
.itemID
= lpitem
->wID
;
696 drawItem
.itemAction
= odaction
;
697 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
698 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
699 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
700 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
701 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
702 drawItem
.hwndItem
= (HWND
)hmenu
;
704 drawItem
.rcItem
= *rect
;
705 drawItem
.itemData
= lpitem
->dwItemData
;
706 /* some applications make this assumption on the DC's origin */
707 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
708 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
709 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
710 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
715 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
716 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
717 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
718 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
719 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
722 InflateRect(&r
, -1, -1);
723 if (0 != (lpitem
->fState
& MF_HILITE
))
725 flags
|= DFCS_PUSHED
;
727 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
731 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
734 hdcMem
= CreateCompatibleDC( hdc
);
735 SelectObject( hdcMem
, bmp
);
737 /* handle fontsize > bitmap_height */
738 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
740 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
741 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
742 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
743 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
747 /***********************************************************************
750 * Calculate the size of the menu item and store it in lpitem->rect.
752 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
753 INT orgX
, INT orgY
, BOOL menuBar
)
756 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
759 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
761 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
763 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
765 if (lpitem
->fType
& MF_OWNERDRAW
)
767 MEASUREITEMSTRUCT mis
;
768 mis
.CtlType
= ODT_MENU
;
770 mis
.itemID
= lpitem
->wID
;
771 mis
.itemData
= lpitem
->dwItemData
;
772 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
774 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
775 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
776 * width of a menufont character to the width of an owner-drawn menu.
778 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
781 /* under at least win95 you seem to be given a standard
782 height for the menu and the height value is ignored */
783 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
785 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
787 TRACE("id=%04lx size=%dx%d\n",
788 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
792 if (lpitem
->fType
& MF_SEPARATOR
)
794 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
796 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
802 if (lpitem
->hbmpItem
)
807 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
808 /* Keep the size of the bitmap in callback mode to be able
809 * to draw it correctly */
810 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
811 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
812 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
814 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
815 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
817 MenuSetRosMenuInfo(MenuInfo
);
818 itemheight
= size
.cy
+ 2;
820 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
821 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
822 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
823 lpitem
->dxTab
= lpitem
->Rect
.right
;
824 lpitem
->Rect
.right
+= check_bitmap_width
;
825 } else /* hbmpItem & MenuBar */ {
826 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
827 lpitem
->Rect
.right
+= size
.cx
;
828 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
829 itemheight
= size
.cy
;
831 /* Special case: Minimize button doesn't have a space behind it. */
832 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
833 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
834 lpitem
->Rect
.right
-= 1;
838 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
839 lpitem
->Rect
.right
+= check_bitmap_width
;
840 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
841 lpitem
->dxTab
= lpitem
->Rect
.right
;
842 lpitem
->Rect
.right
+= check_bitmap_width
;
845 /* it must be a text item - unless it's the system menu */
846 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
847 HFONT hfontOld
= NULL
;
848 RECT rc
= lpitem
->Rect
;
849 LONG txtheight
, txtwidth
;
851 if ( lpitem
->fState
& MFS_DEFAULT
) {
852 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
855 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
856 DT_SINGLELINE
|DT_CALCRECT
);
857 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
858 itemheight
= max( max( itemheight
, txtheight
),
859 GetSystemMetrics( SM_CYMENU
) - 1);
860 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
862 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
865 int n
= (int)( p
- lpitem
->dwTypeData
);
866 /* Item contains a tab (only meaningful in popup menus) */
867 /* get text size before the tab */
868 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
869 DT_SINGLELINE
|DT_CALCRECT
);
870 txtwidth
= rc
.right
- rc
.left
;
871 p
+= 1; /* advance past the Tab */
872 /* get text size after the tab */
873 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
874 DT_SINGLELINE
|DT_CALCRECT
);
875 lpitem
->dxTab
+= txtwidth
;
876 txtheight
= max( txtheight
, tmpheight
);
877 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
878 tmprc
.right
- tmprc
.left
; /* space for the short cut */
880 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
881 DT_SINGLELINE
|DT_CALCRECT
);
882 txtwidth
= rc
.right
- rc
.left
;
883 lpitem
->dxTab
+= txtwidth
;
885 lpitem
->Rect
.right
+= 2 + txtwidth
;
886 itemheight
= max( itemheight
,
887 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
889 if (hfontOld
) SelectObject (hdc
, hfontOld
);
890 } else if( menuBar
) {
891 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
893 lpitem
->Rect
.bottom
+= itemheight
;
894 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
897 /***********************************************************************
898 * MenuPopupMenuCalcSize
900 * Calculate the size of a popup menu.
902 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
904 ROSMENUITEMINFO lpitem
;
907 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
909 MenuInfo
->Width
= MenuInfo
->Height
= 0;
910 if (MenuInfo
->MenuItemCount
== 0)
912 MenuSetRosMenuInfo(MenuInfo
);
917 SelectObject( hdc
, hMenuFont
);
922 MenuInfo
->maxBmpSize
.cx
= 0;
923 MenuInfo
->maxBmpSize
.cy
= 0;
925 MenuInitRosMenuItemInfo(&lpitem
);
926 while (start
< MenuInfo
->MenuItemCount
)
931 maxTab
= maxTabWidth
= 0;
933 /* Parse items until column break or end of menu */
934 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
936 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
938 MenuCleanupRosMenuItemInfo(&lpitem
);
939 MenuSetRosMenuInfo(MenuInfo
);
943 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
945 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
946 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
948 MenuCleanupRosMenuItemInfo(&lpitem
);
949 MenuSetRosMenuInfo(MenuInfo
);
952 // Not sure here,, The patch from wine removes this.
953 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
957 maxX
= max(maxX
, lpitem
.Rect
.right
);
958 orgY
= lpitem
.Rect
.bottom
;
959 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
961 maxTab
= max( maxTab
, lpitem
.dxTab
);
962 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
966 /* Finish the column (set all items to the largest width found) */
967 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
970 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
972 lpitem
.Rect
.right
= maxX
;
973 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
975 lpitem
.dxTab
= maxTab
;
977 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
981 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
984 MenuInfo
->Width
= maxX
;
986 /* space for 3d border */
987 MenuInfo
->Height
+= 2;
988 MenuInfo
->Width
+= 2;
990 MenuCleanupRosMenuItemInfo(&lpitem
);
991 MenuSetRosMenuInfo(MenuInfo
);
995 /***********************************************************************
996 * MenuMenuBarCalcSize
998 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
999 * height is off by 1 pixel which causes lengthy window relocations when
1000 * active document window is maximized/restored.
1002 * Calculate the size of the menu bar.
1004 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1005 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1007 ROSMENUITEMINFO ItemInfo
;
1008 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1010 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1011 if (MenuInfo
->MenuItemCount
== 0) return;
1012 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1013 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1014 MenuInfo
->Height
= 0;
1015 maxY
= lprect
->top
+ 1;
1019 MenuInfo
->maxBmpSize
.cx
= 0;
1020 MenuInfo
->maxBmpSize
.cy
= 0;
1022 MenuInitRosMenuItemInfo(&ItemInfo
);
1023 while (start
< MenuInfo
->MenuItemCount
)
1025 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1027 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1030 orgX
= lprect
->left
;
1033 /* Parse items until line break or end of menu */
1034 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1036 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1038 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1040 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1041 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1042 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1044 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1048 if (ItemInfo
.Rect
.right
> lprect
->right
)
1050 if (i
!= start
) break;
1051 else ItemInfo
.Rect
.right
= lprect
->right
;
1053 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1054 orgX
= ItemInfo
.Rect
.right
;
1055 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1057 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1059 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1065 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1066 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1068 /* Finish the line (set all items to the largest height found) */
1071 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1073 ItemInfo
.Rect
.bottom
= maxY
;
1074 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1079 start
= i
; /* This works! */
1083 lprect
->bottom
= maxY
;
1084 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1085 MenuSetRosMenuInfo(MenuInfo
);
1089 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1090 /* the last item (if several lines, only move the last line) */
1091 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1093 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1096 orgY
= ItemInfo
.Rect
.top
;
1097 orgX
= lprect
->right
;
1098 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1104 if (ItemInfo
.Rect
.top
!= orgY
)
1106 break; /* Other line */
1108 if (orgX
<= ItemInfo
.Rect
.right
)
1110 break; /* Too far right already */
1112 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1113 ItemInfo
.Rect
.right
= orgX
;
1114 orgX
= ItemInfo
.Rect
.left
;
1115 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1116 if (helpPos
+ 1 <= i
&&
1117 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1119 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1125 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1128 /***********************************************************************
1131 * Draw a single menu item.
1133 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1134 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1138 BOOL flat_menu
= FALSE
;
1140 PWND Wnd
= ValidateHwnd(hWnd
);
1145 if (lpitem
->fType
& MF_SYSMENU
)
1147 if ( (Wnd
->style
& WS_MINIMIZE
))
1149 UserGetInsideRectNC(Wnd
, &rect
);
1150 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1151 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1156 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1157 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1161 if (lpitem
->fState
& MF_HILITE
)
1163 if(menuBar
&& !flat_menu
) {
1164 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1165 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1167 if (lpitem
->fState
& MF_GRAYED
)
1168 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1170 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1171 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1176 if (lpitem
->fState
& MF_GRAYED
)
1177 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1179 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1180 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1183 rect
= lpitem
->Rect
;
1185 if (lpitem
->fType
& MF_OWNERDRAW
)
1188 ** Experimentation under Windows reveals that an owner-drawn
1189 ** menu is given the rectangle which includes the space it requested
1190 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1191 ** and a popup-menu arrow. This is the value of lpitem->rect.
1192 ** Windows will leave all drawing to the application except for
1193 ** the popup-menu arrow. Windows always draws that itself, after
1194 ** the menu owner has finished drawing.
1198 dis
.CtlType
= ODT_MENU
;
1200 dis
.itemID
= lpitem
->wID
;
1201 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1203 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1204 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1205 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1206 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1207 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1210 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1211 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1212 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1213 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1215 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1216 /* Draw the popup-menu arrow */
1217 if (lpitem
->hSubMenu
)
1220 CopyRect(&rectTemp
, &rect
);
1221 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1222 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1227 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1229 if (lpitem
->fState
& MF_HILITE
)
1233 InflateRect (&rect
, -1, -1);
1234 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1235 InflateRect (&rect
, 1, 1);
1236 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1241 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1243 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1247 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1249 SetBkMode( hdc
, TRANSPARENT
);
1251 /* vertical separator */
1252 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1259 rc
.bottom
= Height
- 3;
1262 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1263 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1264 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1265 LineTo( hdc
, rc
.left
, rc
.bottom
);
1266 SelectObject( hdc
, oldPen
);
1269 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1272 /* horizontal separator */
1273 if (lpitem
->fType
& MF_SEPARATOR
)
1280 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1283 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1284 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1285 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1286 LineTo( hdc
, rc
.right
, rc
.top
);
1287 SelectObject( hdc
, oldPen
);
1290 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1295 /* helper lines for debugging */
1296 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1297 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1298 SelectObject(hdc
, GetStockObject(DC_PEN
));
1299 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1300 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1301 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1307 INT y
= rect
.top
+ rect
.bottom
;
1309 BOOL checked
= FALSE
;
1310 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1311 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1312 /* Draw the check mark
1315 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1317 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1318 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1319 lpitem
->hbmpUnchecked
;
1320 if (bm
) /* we have a custom bitmap */
1322 HDC hdcMem
= CreateCompatibleDC( hdc
);
1324 SelectObject( hdcMem
, bm
);
1325 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1326 check_bitmap_width
, check_bitmap_height
,
1327 hdcMem
, 0, 0, SRCCOPY
);
1331 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1334 CopyRect(&r
, &rect
);
1335 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1336 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1337 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1338 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1342 if ( lpitem
->hbmpItem
)
1345 CopyRect(&bmpRect
, &rect
);
1346 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1347 bmpRect
.left
+= check_bitmap_width
+ 2;
1348 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1350 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1351 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1354 /* Draw the popup-menu arrow */
1355 if (lpitem
->hSubMenu
)
1358 CopyRect(&rectTemp
, &rect
);
1359 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1360 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1363 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1364 rect
.left
+= check_bitmap_width
;
1365 rect
.right
-= check_bitmap_width
;
1367 else if( lpitem
->hbmpItem
)
1368 { /* Draw the bitmap */
1369 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1372 /* process text if present */
1378 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1379 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1381 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1382 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1384 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1386 if ( lpitem
->fState
& MFS_DEFAULT
)
1388 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1392 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1393 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1396 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1399 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1400 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1404 if(lpitem
->fState
& MF_GRAYED
)
1406 if (!(lpitem
->fState
& MF_HILITE
) )
1408 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1409 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1410 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1411 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1413 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1416 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1418 /* paint the shortcut text */
1419 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1421 if (L
'\t' == Text
[i
])
1423 rect
.left
= lpitem
->dxTab
;
1424 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1428 rect
.right
= lpitem
->dxTab
;
1429 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1432 if (lpitem
->fState
& MF_GRAYED
)
1434 if (!(lpitem
->fState
& MF_HILITE
) )
1436 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1437 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1438 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1439 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1441 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1443 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1447 SelectObject (hdc
, hfontOld
);
1451 /***********************************************************************
1454 * Paint a popup menu.
1456 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1458 HBRUSH hPrevBrush
= 0;
1461 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1463 GetClientRect( hwnd
, &rect
);
1465 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1466 && (SelectObject( hdc
, hMenuFont
)))
1470 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1472 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1475 BOOL flat_menu
= FALSE
;
1476 ROSMENUINFO MenuInfo
;
1477 ROSMENUITEMINFO ItemInfo
;
1479 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1481 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1483 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1485 /* draw menu items */
1486 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1490 MenuInitRosMenuItemInfo(&ItemInfo
);
1492 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1494 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1496 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1497 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1501 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1505 SelectObject( hdc
, hPrevBrush
);
1510 /***********************************************************************
1513 * Paint a menu bar. Returns the height of the menu bar.
1514 * called from [windows/nonclient.c]
1516 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1521 HMENU hMenu
= GetMenu(hwnd
);
1523 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1525 return GetSystemMetrics(SM_CYMENU
);
1530 hfontOld
= SelectObject(hDC
, hMenuFont
);
1532 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1534 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1536 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1537 return lppop
.Height
;
1540 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1543 /***********************************************************************
1546 * Display a popup menu.
1548 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1549 INT x
, INT y
, INT xanchor
, INT yanchor
)
1551 ROSMENUINFO MenuInfo
;
1552 ROSMENUITEMINFO ItemInfo
;
1559 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1560 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1562 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1563 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1565 MenuInitRosMenuItemInfo(&ItemInfo
);
1566 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1568 ItemInfo
.fMask
|= MIIM_STATE
;
1569 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1570 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1572 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1573 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1576 /* store the owner for DrawItem */
1577 if (!IsWindow(hwndOwner
))
1579 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1582 MenuInfo
.WndOwner
= hwndOwner
;
1583 MenuSetRosMenuInfo(&MenuInfo
);
1585 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1587 /* adjust popup menu pos so that it fits within the desktop */
1589 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1590 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1592 /* FIXME: should use item rect */
1595 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1596 info
.cbSize
= sizeof(info
);
1597 GetMonitorInfoW( monitor
, &info
);
1599 if (flags
& TPM_LAYOUTRTL
)
1601 ex_style
= WS_EX_LAYOUTRTL
;
1602 flags
^= TPM_RIGHTALIGN
;
1604 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1605 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1607 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1608 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1610 if( x
+ width
> info
.rcMonitor
.right
)
1612 if( xanchor
&& x
>= width
- xanchor
)
1613 x
-= width
- xanchor
;
1615 if( x
+ width
> info
.rcMonitor
.right
)
1616 x
= info
.rcMonitor
.right
- width
;
1618 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
1620 if( y
+ height
> info
.rcMonitor
.bottom
)
1622 if( yanchor
&& y
>= height
+ yanchor
)
1623 y
-= height
+ yanchor
;
1625 if( y
+ height
> info
.rcMonitor
.bottom
)
1626 y
= info
.rcMonitor
.bottom
- height
;
1628 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
1630 /* NOTE: In Windows, top menu popup is not owned. */
1631 MenuInfo
.Wnd
= CreateWindowExW( ex_style
, WC_MENU
, NULL
,
1632 WS_POPUP
, x
, y
, width
, height
,
1633 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1634 (LPVOID
) MenuInfo
.Self
);
1635 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1637 top_popup
= MenuInfo
.Wnd
;
1638 top_popup_hmenu
= hmenu
;
1641 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1643 /* Display the window */
1645 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1646 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1647 UpdateWindow( MenuInfo
.Wnd
);
1652 /***********************************************************************
1655 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1656 BOOL sendMenuSelect
, HMENU topmenu
)
1658 ROSMENUITEMINFO ItemInfo
;
1659 ROSMENUINFO TopMenuInfo
;
1662 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1664 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1665 if (hmenu
->FocusedItem
== wIndex
) return;
1666 if (hmenu
->Flags
& MNF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1667 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1669 top_popup
= hmenu
->Wnd
;
1670 top_popup_hmenu
= hmenu
->Self
;
1673 SelectObject( hdc
, hMenuFont
);
1675 MenuInitRosMenuItemInfo(&ItemInfo
);
1677 /* Clear previous highlighted item */
1678 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1680 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1682 ItemInfo
.fMask
|= MIIM_STATE
;
1683 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1684 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1686 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1687 hmenu
->Height
, !(hmenu
->Flags
& MNF_POPUP
),
1691 /* Highlight new item (if any) */
1692 hmenu
->FocusedItem
= wIndex
;
1693 MenuSetRosMenuInfo(hmenu
);
1694 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1696 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1698 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1700 ItemInfo
.fMask
|= MIIM_STATE
;
1701 ItemInfo
.fState
|= MF_HILITE
;
1702 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1703 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1704 &ItemInfo
, hmenu
->Height
, !(hmenu
->Flags
& MNF_POPUP
),
1709 WPARAM wParam
= MAKEWPARAM( ItemInfo
.hSubMenu
? wIndex
: ItemInfo
.wID
,
1710 ItemInfo
.fType
| ItemInfo
.fState
|
1711 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
1712 (hmenu
->Flags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
1714 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) hmenu
->Self
);
1718 else if (sendMenuSelect
)
1723 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1724 if (pos
!= NO_SELECTED_ITEM
)
1726 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1727 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1729 WPARAM wParam
= MAKEWPARAM( Pos
, ItemInfo
.fType
| ItemInfo
.fState
|
1730 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
1731 (TopMenuInfo
.Flags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
1733 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) topmenu
);
1738 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1739 ReleaseDC(hmenu
->Wnd
, hdc
);
1742 /***********************************************************************
1745 * Moves currently selected item according to the Offset parameter.
1746 * If there is no selection then it should select the last item if
1747 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1749 static void FASTCALL
1750 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1753 ROSMENUITEMINFO ItemInfo
;
1756 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1758 /* Prevent looping */
1759 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1761 else if (Offset
< -1)
1763 else if (Offset
> 1)
1766 MenuInitRosMenuItemInfo(&ItemInfo
);
1768 OrigPos
= MenuInfo
->FocusedItem
;
1769 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1776 i
= MenuInfo
->FocusedItem
;
1783 /* Clip and wrap around */
1786 i
= MenuInfo
->MenuItemCount
- 1;
1788 else if (i
>= MenuInfo
->MenuItemCount
)
1792 /* If this is a good candidate; */
1793 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1794 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1796 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1797 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1800 } while (i
!= OrigPos
);
1803 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1807 // This breaks some test results. Should handle A2U if called!
1809 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1814 pWnd
= ValidateHwnd(Wnd
);
1819 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1823 if (pWnd
->fnid
!= FNID_MENU
)
1825 ERR("Wrong window class for Menu!\n");
1832 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1838 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1839 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1843 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1844 return MA_NOACTIVATE
;
1849 BeginPaint(Wnd
, &ps
);
1850 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1855 case WM_PRINTCLIENT
:
1857 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1858 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1866 /* zero out global pointer in case resident popup window was destroyed. */
1867 if (Wnd
== top_popup
)
1870 top_popup_hmenu
= NULL
;
1876 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
1883 if (0 == GetWindowLongPtrA(Wnd
, 0))
1885 OutputDebugStringA("no menu to display\n");
1890 SetWindowLongPtrA(Wnd
, 0, 0);
1894 case MM_SETMENUHANDLE
:
1895 SetWindowLongPtrA(Wnd
, 0, wParam
);
1898 case MM_GETMENUHANDLE
:
1900 return GetWindowLongPtrA(Wnd
, 0);
1903 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1909 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1911 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
1914 pWnd
= ValidateHwnd(Wnd
);
1919 if (Message
!= WM_NCCREATE
)
1921 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1923 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1927 if (pWnd
->fnid
!= FNID_MENU
)
1929 ERR("Wrong window class for Menu!\n");
1936 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1942 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1943 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1947 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1948 return MA_NOACTIVATE
;
1953 BeginPaint(Wnd
, &ps
);
1954 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1959 case WM_PRINTCLIENT
:
1961 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1962 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1970 /* zero out global pointer in case resident popup window was destroyed. */
1971 if (Wnd
== top_popup
)
1974 top_popup_hmenu
= NULL
;
1981 if (0 == GetWindowLongPtrW(Wnd
, 0))
1983 OutputDebugStringA("no menu to display\n");
1988 SetWindowLongPtrW(Wnd
, 0, 0);
1992 case MM_SETMENUHANDLE
:
1993 SetWindowLongPtrW(Wnd
, 0, wParam
);
1996 case MM_GETMENUHANDLE
:
1998 return GetWindowLongPtrW(Wnd
, 0);
2001 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2007 /**********************************************************************
2008 * MENU_ParseResource
2010 * Parse a standard menu resource and add items to the menu.
2011 * Return a pointer to the end of the resource.
2013 * NOTE: flags is equivalent to the mtOption field
2015 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2024 flags
= GET_WORD(res
);
2026 /* remove MF_END flag before passing it to AppendMenu()! */
2027 end
= (flags
& MF_END
);
2028 if(end
) flags
^= MF_END
;
2030 res
+= sizeof(WORD
);
2031 if(!(flags
& MF_POPUP
))
2034 res
+= sizeof(WORD
);
2037 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2039 if (flags
& MF_POPUP
)
2041 hSubMenu
= CreatePopupMenu();
2042 if(!hSubMenu
) return NULL
;
2043 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
2044 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
2046 else /* Not a popup */
2048 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2055 /**********************************************************************
2056 * MENUEX_ParseResource
2058 * Parse an extended menu resource and add items to the menu.
2059 * Return a pointer to the end of the resource.
2061 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2068 mii
.cbSize
= sizeof(mii
);
2069 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2070 mii
.fType
= GET_DWORD(res
);
2071 res
+= sizeof(DWORD
);
2072 mii
.fState
= GET_DWORD(res
);
2073 res
+= sizeof(DWORD
);
2074 mii
.wID
= GET_DWORD(res
);
2075 res
+= sizeof(DWORD
);
2076 resinfo
= GET_WORD(res
);
2077 res
+= sizeof(WORD
);
2078 /* Align the text on a word boundary. */
2079 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2080 mii
.dwTypeData
= (LPWSTR
)res
;
2081 mii
.cch
= strlenW(mii
.dwTypeData
);
2082 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2083 /* Align the following fields on a dword boundary. */
2084 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2086 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2087 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2089 if (resinfo
& 1) /* Pop-up? */
2091 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2092 res
+= sizeof(DWORD
);
2093 mii
.hSubMenu
= CreatePopupMenu();
2096 ERR("CreatePopupMenu failed\n");
2100 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2102 ERR("MENUEX_ParseResource failed\n");
2103 DestroyMenu(mii
.hSubMenu
);
2106 mii
.fMask
|= MIIM_SUBMENU
;
2108 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
2110 mii
.fType
|= MF_SEPARATOR
;
2112 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2113 } while (!(resinfo
& MF_END
));
2118 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2120 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2121 LRESULT Result
= (LRESULT
)hmenu
;
2122 MENUINFO menuinfo
= {0};
2123 MENUITEMINFOW info
= {0};
2125 // removing space for checkboxes from menu
2126 menuinfo
.cbSize
= sizeof(menuinfo
);
2127 menuinfo
.fMask
= MIM_STYLE
;
2128 GetMenuInfo(hmenu
, &menuinfo
);
2129 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2130 SetMenuInfo(hmenu
, &menuinfo
);
2132 // adding bitmaps to menu items
2133 info
.cbSize
= sizeof(info
);
2134 info
.fMask
|= MIIM_BITMAP
;
2135 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2136 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2137 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2138 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2139 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2140 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2141 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2142 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2144 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2151 NONCLIENTMETRICSW ncm
;
2153 /* get the menu font */
2154 if(!hMenuFont
|| !hMenuFontBold
)
2156 ncm
.cbSize
= sizeof(ncm
);
2157 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2159 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2163 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2164 if(hMenuFont
== NULL
)
2166 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2170 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2171 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2172 if(hMenuFontBold
== NULL
)
2174 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2175 DeleteObject(hMenuFont
);
2189 DeleteObject(hMenuFont
);
2195 DeleteObject(hMenuFontBold
);
2196 hMenuFontBold
= NULL
;
2200 /***********************************************************************
2201 * DrawMenuBarTemp (USER32.@)
2205 * called by W98SE desk.cpl Control Panel Applet
2207 * Not 100% sure about the param names, but close.
2212 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2214 ROSMENUINFO MenuInfo
;
2215 ROSMENUITEMINFO ItemInfo
;
2217 HFONT FontOld
= NULL
;
2218 BOOL flat_menu
= FALSE
;
2220 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2224 Menu
= GetMenu(Wnd
);
2232 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2234 return GetSystemMetrics(SM_CYMENU
);
2237 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2239 FontOld
= SelectObject(DC
, Font
);
2241 if (0 == MenuInfo
.Height
)
2243 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2246 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2248 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2250 SelectObject(DC
, GetStockObject(DC_PEN
));
2251 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2252 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2253 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2255 if (0 == MenuInfo
.MenuItemCount
)
2257 SelectObject(DC
, FontOld
);
2258 return GetSystemMetrics(SM_CYMENU
);
2261 MenuInitRosMenuItemInfo(&ItemInfo
);
2262 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2264 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2266 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2267 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2270 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2272 SelectObject(DC
, FontOld
);
2274 return MenuInfo
.Height
;
2277 /***********************************************************************
2280 * Display the sub-menu of the selected item of this menu.
2281 * Return the handle of the submenu, or menu if no submenu to display.
2283 static HMENU FASTCALL
2284 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2286 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2288 ROSMENUITEMINFO ItemInfo
;
2289 ROSMENUINFO SubMenuInfo
;
2293 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2295 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2297 return MenuInfo
->Self
;
2300 MenuInitRosMenuItemInfo(&ItemInfo
);
2301 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2303 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2304 return MenuInfo
->Self
;
2306 if (0 == (ItemInfo
.hSubMenu
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2308 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2309 return MenuInfo
->Self
;
2312 /* message must be sent before using item,
2313 because nearly everything may be changed by the application ! */
2315 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2316 if (0 == (Flags
& TPM_NONOTIFY
))
2318 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2319 MAKELPARAM(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2322 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2324 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2325 return MenuInfo
->Self
;
2327 Rect
= ItemInfo
.Rect
;
2329 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2330 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2332 if (0 != (MenuInfo
->Flags
& MNF_POPUP
))
2334 Dc
= GetDC(MenuInfo
->Wnd
);
2338 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2341 SelectObject(Dc
, hMenuFont
);
2342 ItemInfo
.fMask
|= MIIM_STATE
;
2343 ItemInfo
.fState
|= MF_HILITE
;
2344 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2345 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2346 ! (MenuInfo
->Flags
& MNF_POPUP
), ODA_DRAWENTIRE
);
2347 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2350 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2351 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2353 ItemInfo
.Rect
= Rect
;
2356 ItemInfo
.fMask
|= MIIM_STATE
;
2357 ItemInfo
.fState
|= MF_MOUSESELECT
;
2358 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2360 if (IS_SYSTEM_MENU(MenuInfo
))
2362 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2363 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2364 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
;
2365 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2366 Rect
.top
= Rect
.bottom
;
2367 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2368 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2372 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2373 if (0 != (MenuInfo
->Flags
& MNF_POPUP
))
2375 if(Flags
& TPM_LAYOUTRTL
)
2376 Rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
2378 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2379 Rect
.top
+= ItemInfo
.Rect
.top
- MENU_TOP_MARGIN
;//3;
2380 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2381 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
2382 - GetSystemMetrics(SM_CYBORDER
);
2386 if(Flags
& TPM_LAYOUTRTL
)
2387 Rect
.left
+= Rect
.right
- ItemInfo
.Rect
.left
;
2389 Rect
.left
+= ItemInfo
.Rect
.left
;
2390 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2391 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2392 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2396 /* use default alignment for submenus */
2397 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
2399 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2400 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2401 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2403 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2406 Ret
= ItemInfo
.hSubMenu
;
2407 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2412 /**********************************************************************
2415 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2417 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2419 void MENU_EndMenu( HWND hwnd
)
2421 ROSMENUINFO MenuInfo
;
2423 if (top_popup_hmenu
)
2424 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2425 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2428 /***********************************************************************
2431 * Hide the sub-popup menus of this menu.
2433 static void FASTCALL
2434 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2435 BOOL SendMenuSelect
, UINT wFlags
)
2437 ROSMENUINFO SubMenuInfo
;
2438 ROSMENUITEMINFO ItemInfo
;
2440 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2442 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2444 MenuInitRosMenuItemInfo(&ItemInfo
);
2445 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2446 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2447 || 0 == (ItemInfo
.hSubMenu
)
2448 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2450 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2453 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2454 ItemInfo
.fMask
|= MIIM_STATE
;
2455 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2456 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2458 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2459 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2460 DestroyWindow(SubMenuInfo
.Wnd
);
2461 SubMenuInfo
.Wnd
= NULL
;
2462 MenuSetRosMenuInfo(&SubMenuInfo
);
2464 if (!(wFlags
& TPM_NONOTIFY
))
2465 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2466 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2471 /***********************************************************************
2472 * MenuSwitchTracking
2474 * Helper function for menu navigation routines.
2476 static void FASTCALL
2477 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2479 ROSMENUINFO TopMenuInfo
;
2481 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2483 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2484 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2485 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MNF_POPUP
))
2487 /* both are top level menus (system and menu-bar) */
2488 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2489 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2490 Mt
->TopMenu
= PtMenuInfo
->Self
;
2494 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2497 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2500 /***********************************************************************
2501 * MenuExecFocusedItem
2503 * Execute a menu item (for instance when user pressed Enter).
2504 * Return the wID of the executed item. Otherwise, -1 indicating
2505 * that no menu item was executed, -2 if a popup is shown;
2506 * Have to receive the flags for the TrackPopupMenu options to avoid
2507 * sending unwanted message.
2511 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2513 ROSMENUITEMINFO ItemInfo
;
2516 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2518 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2523 MenuInitRosMenuItemInfo(&ItemInfo
);
2524 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2526 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2530 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2532 if (0 == (ItemInfo
.hSubMenu
))
2534 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2535 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2537 /* If TPM_RETURNCMD is set you return the id, but
2538 do not send a message to the owner */
2539 if (0 == (Flags
& TPM_RETURNCMD
))
2541 if (0 != (MenuInfo
->Flags
& MNF_SYSDESKMN
))
2543 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2544 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2548 ROSMENUINFO topmenuI
;
2549 BOOL ret
= MenuGetRosMenuInfo(&topmenuI
, Mt
->TopMenu
);
2550 DWORD dwStyle
= MenuInfo
->dwStyle
| (ret
? topmenuI
.dwStyle
: 0);
2552 if (dwStyle
& MNS_NOTIFYBYPOS
)
2553 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
, MenuInfo
->FocusedItem
, (LPARAM
)MenuInfo
->Self
);
2555 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2559 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2565 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2572 /***********************************************************************
2575 * Return TRUE if we can go on with menu tracking.
2577 static BOOL FASTCALL
2578 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2581 ROSMENUINFO MenuInfo
;
2582 ROSMENUITEMINFO Item
;
2584 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2588 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2592 if (IS_SYSTEM_MENU(&MenuInfo
))
2598 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2600 MenuInitRosMenuItemInfo(&Item
);
2601 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2603 MenuCleanupRosMenuItemInfo(&Item
);
2607 if (!(Item
.fType
& MF_SEPARATOR
) &&
2608 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2610 if (MenuInfo
.FocusedItem
!= Index
)
2612 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2615 /* If the popup menu is not already "popped" */
2616 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2618 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2622 MenuCleanupRosMenuItemInfo(&Item
);
2627 /* else the click was on the menu bar, finish the tracking */
2632 /***********************************************************************
2635 * Return the value of MenuExecFocusedItem if
2636 * the selected item was not a popup. Else open the popup.
2637 * A -1 return value indicates that we go on with menu tracking.
2641 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2644 ROSMENUINFO MenuInfo
;
2645 ROSMENUITEMINFO ItemInfo
;
2647 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2652 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2657 if (! IS_SYSTEM_MENU(&MenuInfo
))
2659 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2661 MenuInitRosMenuItemInfo(&ItemInfo
);
2662 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2663 MenuInfo
.FocusedItem
== Id
)
2665 if (0 == (ItemInfo
.hSubMenu
))
2667 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2668 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2669 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2671 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2673 /* If we are dealing with the top-level menu */
2674 /* and this is a click on an already "popped" item: */
2675 /* Stop the menu tracking and close the opened submenus */
2676 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2678 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2682 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2683 MenuInfo
.TimeToHide
= TRUE
;
2684 MenuSetRosMenuInfo(&MenuInfo
);
2690 /***********************************************************************
2693 * Walks menu chain trying to find a menu pt maps to.
2695 static HMENU FASTCALL
2696 MenuPtMenu(HMENU Menu
, POINT Pt
)
2698 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2699 ROSMENUINFO MenuInfo
;
2700 ROSMENUITEMINFO ItemInfo
;
2704 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2709 /* try subpopup first (if any) */
2710 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2712 MenuInitRosMenuItemInfo(&ItemInfo
);
2713 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2714 0 != (ItemInfo
.hSubMenu
) &&
2715 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2717 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2720 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2724 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2727 /* check the current window (avoiding WM_HITTEST) */
2728 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2729 if (0 != (MenuInfo
.Flags
& MNF_POPUP
))
2731 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2736 else if (HTSYSMENU
== Ht
)
2738 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2740 else if (HTMENU
== Ht
)
2742 Ret
= GetMenu(MenuInfo
.Wnd
);
2748 /***********************************************************************
2751 * Return TRUE if we can go on with menu tracking.
2753 static BOOL FASTCALL
2754 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2757 ROSMENUINFO MenuInfo
;
2758 ROSMENUITEMINFO ItemInfo
;
2762 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2766 if (IS_SYSTEM_MENU(&MenuInfo
))
2772 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2777 Index
= NO_SELECTED_ITEM
;
2780 if (NO_SELECTED_ITEM
== Index
)
2782 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2783 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2785 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2789 else if (MenuInfo
.FocusedItem
!= Index
)
2791 MenuInitRosMenuItemInfo(&ItemInfo
);
2792 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2793 !(ItemInfo
.fType
& MF_SEPARATOR
))
2795 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2796 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2797 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2799 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2805 /***********************************************************************
2808 * Return the handle of the selected sub-popup menu (if any).
2810 static HMENU FASTCALL
2811 MenuGetSubPopup(HMENU Menu
)
2813 ROSMENUINFO MenuInfo
;
2814 ROSMENUITEMINFO ItemInfo
;
2816 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2817 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2822 MenuInitRosMenuItemInfo(&ItemInfo
);
2823 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2825 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2828 if (0 != (ItemInfo
.hSubMenu
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2830 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2831 return ItemInfo
.hSubMenu
;
2834 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2838 /***********************************************************************
2841 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2843 static LRESULT FASTCALL
2844 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2846 ROSMENUINFO TopMenuInfo
;
2847 ROSMENUINFO MenuInfo
;
2849 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2851 return (LRESULT
) FALSE
;
2854 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2855 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2857 MDINEXTMENU NextMenu
;
2862 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2863 NextMenu
.hmenuNext
= NULL
;
2864 NextMenu
.hwndNext
= NULL
;
2865 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2867 TRACE("%p [%p] -> %p [%p]\n",
2868 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2870 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2872 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2873 NewWnd
= Mt
->OwnerWnd
;
2874 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2876 /* switch to the menu bar */
2878 if (0 != (Style
& WS_CHILD
)
2879 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2886 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2890 Id
= MenuInfo
.MenuItemCount
- 1;
2893 else if (0 != (Style
& WS_SYSMENU
))
2895 /* switch to the system menu */
2896 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2903 else /* application returned a new menu to switch to */
2905 NewMenu
= NextMenu
.hmenuNext
;
2906 NewWnd
= NextMenu
.hwndNext
;
2908 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2910 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2912 if (0 != (Style
& WS_SYSMENU
)
2913 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2915 /* get the real system menu */
2916 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2918 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2920 /* FIXME: Not sure what to do here;
2921 * perhaps try to track NewMenu as a popup? */
2923 WARN(" -- got confused.\n");
2933 if (NewMenu
!= Mt
->TopMenu
)
2935 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2937 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2939 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2943 if (NewWnd
!= Mt
->OwnerWnd
)
2945 Mt
->OwnerWnd
= NewWnd
;
2946 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
2947 SetCapture(Mt
->OwnerWnd
); // 2
2950 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2951 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2953 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2962 /***********************************************************************
2965 * The idea is not to show the popup if the next input message is
2966 * going to hide it anyway.
2968 static BOOL FASTCALL
2969 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
2973 msg
.hwnd
= Mt
->OwnerWnd
;
2975 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
2976 // Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
2981 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2982 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2984 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2985 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2986 if( msg
.message
== WM_KEYDOWN
&&
2987 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2989 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2995 /* failures go through this */
2996 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3000 /***********************************************************************
3003 * Handle a VK_ESCAPE key event in a menu.
3005 static BOOL FASTCALL
3006 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3008 BOOL EndMenu
= TRUE
;
3009 ROSMENUINFO MenuInfo
;
3010 HMENU MenuTmp
, MenuPrev
;
3012 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3014 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3015 && 0 != (MenuInfo
.Flags
& MNF_POPUP
))
3017 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3019 /* close topmost popup */
3020 while (MenuTmp
!= Mt
->CurrentMenu
)
3023 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3026 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3028 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3030 Mt
->CurrentMenu
= MenuPrev
;
3038 /***********************************************************************
3041 * Handle a VK_LEFT key event in a menu.
3043 static void FASTCALL
3044 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3046 ROSMENUINFO MenuInfo
;
3047 ROSMENUINFO TopMenuInfo
;
3048 ROSMENUINFO PrevMenuInfo
;
3049 HMENU MenuTmp
, MenuPrev
;
3052 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3054 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3059 /* Try to move 1 column left (if possible) */
3060 if ( (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)) != NO_SELECTED_ITEM
)
3062 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3064 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3069 /* close topmost popup */
3070 while (MenuTmp
!= Mt
->CurrentMenu
)
3073 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3076 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3080 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3081 Mt
->CurrentMenu
= MenuPrev
;
3083 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3087 if ((MenuPrev
== Mt
->TopMenu
) && !(TopMenuInfo
.Flags
& MNF_POPUP
))
3089 /* move menu bar selection if no more popups are left */
3091 if (!MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3093 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3096 if (MenuPrev
!= MenuTmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3098 /* A sublevel menu was displayed - display the next one
3099 * unless there is another displacement coming up */
3101 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3102 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3104 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3111 /***********************************************************************
3114 * Handle a VK_RIGHT key event in a menu.
3116 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3119 ROSMENUINFO MenuInfo
;
3120 ROSMENUINFO CurrentMenuInfo
;
3123 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3124 Mt
->CurrentMenu
, Mt
->TopMenu
);
3126 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3127 if ((MenuInfo
.Flags
& MNF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3129 /* If already displaying a popup, try to display sub-popup */
3131 hmenutmp
= Mt
->CurrentMenu
;
3132 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3134 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3137 /* if subpopup was displayed then we are done */
3138 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3141 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3146 /* Check to see if there's another column */
3147 if ( (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)) != NO_SELECTED_ITEM
)
3149 TRACE("Going to %d.\n", NextCol
);
3150 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3152 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3157 if (!(MenuInfo
.Flags
& MNF_POPUP
)) /* menu bar tracking */
3159 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3161 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3162 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3169 /* try to move to the next item */
3170 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3171 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3173 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3175 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3176 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3178 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3185 /***********************************************************************
3188 * Menu tracking code.
3190 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3191 HWND hwnd
, const RECT
*lprect
)
3194 ROSMENUINFO MenuInfo
;
3195 ROSMENUITEMINFO ItemInfo
;
3197 INT executedMenuId
= -1;
3200 BOOL enterIdleSent
= FALSE
;
3203 mt
.CurrentMenu
= hmenu
;
3209 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3210 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3211 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3215 WARN("Invalid menu handle %p\n", hmenu
);
3216 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3221 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3226 if (wFlags
& TPM_BUTTONDOWN
)
3228 /* Get the result in order to start the tracking or not */
3229 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3230 fEndMenu
= !fRemove
;
3233 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3235 /* owner may not be visible when tracking a popup, so use the menu itself */
3236 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3237 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3238 SetCapture(capture_win
); // 2
3242 BOOL ErrorExit
= FALSE
;
3243 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, TYPE_MENU
);
3244 if (!menu
) /* sometimes happens if I do a window manager close */
3247 /* we have to keep the message in the queue until it's
3248 * clear that menu loop is not over yet. */
3252 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3254 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3255 /* remove the message from the queue */
3256 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3261 if (!ValidateHwnd(mt
.OwnerWnd
) || !ValidateHwnd(MenuInfo
.Wnd
))
3263 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3268 HWND win
= MenuInfo
.Flags
& MNF_POPUP
? MenuInfo
.Wnd
: NULL
;
3269 enterIdleSent
= TRUE
;
3270 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3276 if (ErrorExit
) break; // Gracefully dropout.
3278 /* check if EndMenu() tried to cancel us, by posting this message */
3279 if (msg
.message
== WM_CANCELMODE
)
3281 /* we are now out of the loop */
3284 /* remove the message from the queue */
3285 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3287 /* break out of internal loop, ala ESCAPE */
3291 TranslateMessage( &msg
);
3294 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3295 enterIdleSent
=FALSE
;
3298 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3301 * Use the mouse coordinates in lParam instead of those in the MSG
3302 * struct to properly handle synthetic messages. They are already
3303 * in screen coordinates.
3305 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3306 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3308 /* Find a menu for this mouse event */
3309 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3313 /* no WM_NC... messages in captured state */
3315 case WM_RBUTTONDBLCLK
:
3316 case WM_RBUTTONDOWN
:
3317 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3319 case WM_LBUTTONDBLCLK
:
3320 case WM_LBUTTONDOWN
:
3321 /* If the message belongs to the menu, removes it from the queue */
3322 /* Else, end menu tracking */
3323 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3324 fEndMenu
= !fRemove
;
3328 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3331 /* Check if a menu was selected by the mouse */
3334 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3335 TRACE("executedMenuId %d\n", executedMenuId
);
3337 /* End the loop if executedMenuId is an item ID */
3338 /* or if the job was done (executedMenuId = 0). */
3339 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3341 /* No menu was selected by the mouse */
3342 /* if the function was called by TrackPopupMenu, continue
3343 with the menu tracking. If not, stop it */
3345 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3350 /* the selected menu item must be changed every time */
3351 /* the mouse moves. */
3354 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3356 } /* switch(msg.message) - mouse */
3358 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3360 fRemove
= TRUE
; /* Keyboard messages are always removed */
3374 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3376 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
3377 NO_SELECTED_ITEM
, FALSE
, 0 );
3378 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3379 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3384 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3385 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3387 if (!(MenuInfo
.Flags
& MNF_POPUP
))
3389 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3390 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3392 else /* otherwise try to move selection */
3393 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3394 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3399 MenuKeyLeft( &mt
, wFlags
);
3403 MenuKeyRight( &mt
, wFlags
);
3407 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3413 hi
.cbSize
= sizeof(HELPINFO
);
3414 hi
.iContextType
= HELPINFO_MENUITEM
;
3415 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3417 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
)
3421 MenuInitRosMenuItemInfo(&ItemInfo
);
3422 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3423 MenuInfo
.FocusedItem
,
3426 hi
.iCtrlId
= ItemInfo
.wID
;
3432 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3435 hi
.hItemHandle
= hmenu
;
3436 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3437 hi
.MousePos
= msg
.pt
;
3438 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3445 break; /* WM_KEYDOWN */
3452 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3453 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3455 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3456 fEndMenu
= (executedMenuId
!= -2);
3460 /* Hack to avoid control chars. */
3461 /* We will find a better way real soon... */
3462 if (msg
.wParam
< 32) break;
3464 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3465 LOWORD(msg
.wParam
), FALSE
);
3466 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3467 else if (pos
== (UINT
)-1) MessageBeep(0);
3470 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3472 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3473 fEndMenu
= (executedMenuId
!= -2);
3477 } /* switch(msg.message) - kbd */
3481 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3482 DispatchMessageW( &msg
);
3486 if (!fEndMenu
) fRemove
= TRUE
;
3488 /* finally remove message from the queue */
3490 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3491 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3492 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3495 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3496 SetCapture(NULL
); /* release the capture */
3498 /* If dropdown is still painted and the close box is clicked on
3499 then the menu will be destroyed as part of the DispatchMessage above.
3500 This will then invalidate the menu handle in mt.hTopMenu. We should
3501 check for this first. */
3502 if( IsMenu( mt
.TopMenu
) )
3504 if (IsWindow(mt
.OwnerWnd
))
3506 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3508 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3510 if (MenuInfo
.Flags
& MNF_POPUP
)
3512 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3513 DestroyWindow(MenuInfo
.Wnd
);
3514 MenuInfo
.Wnd
= NULL
;
3516 if (!(wFlags
& TPM_NONOTIFY
))
3517 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3518 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3520 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3523 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3526 /* Reset the variable for hiding menu */
3527 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3529 MenuInfo
.TimeToHide
= FALSE
;
3530 MenuSetRosMenuInfo(&MenuInfo
);
3534 /* The return value is only used by TrackPopupMenu */
3535 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3536 if (executedMenuId
== -1) executedMenuId
= 0;
3537 return executedMenuId
;
3540 /***********************************************************************
3543 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3545 ROSMENUINFO MenuInfo
;
3547 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3551 /* This makes the menus of applications built with Delphi work.
3552 * It also enables menus to be displayed in more than one window,
3553 * but there are some bugs left that need to be fixed in this case.
3555 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
3557 MenuInfo
.Wnd
= hWnd
;
3558 MenuSetRosMenuInfo(&MenuInfo
);
3561 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3562 if (!(wFlags
& TPM_NONOTIFY
))
3563 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3565 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3567 if (!(wFlags
& TPM_NONOTIFY
))
3569 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3570 /* If an app changed/recreated menu bar entries in WM_INITMENU
3571 * menu sizes will be recalculated once the menu created/shown.
3574 if (!MenuInfo
.Height
)
3576 /* app changed/recreated menu bar entries in WM_INITMENU
3577 Recalculate menu sizes else clicks will not work */
3578 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3579 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3584 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
3586 MenuInfo
.Flags
& MNF_SYSDESKMN
? OBJID_SYSMENU
: OBJID_MENU
,
3590 /***********************************************************************
3593 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
3595 TRACE("hwnd=%p\n", hWnd
);
3597 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
3598 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
3601 top_popup_hmenu
= NULL
;
3605 /***********************************************************************
3606 * MenuTrackMouseMenuBar
3608 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3610 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3612 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3613 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3615 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3617 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
3620 /* map point to parent client coordinates */
3621 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3622 if (Parent
!= GetDesktopWindow())
3624 ScreenToClient(Parent
, &pt
);
3627 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3628 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3629 MenuExitTracking(hWnd
, FALSE
);
3634 /***********************************************************************
3635 * MenuTrackKbdMenuBar
3637 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3639 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3641 UINT uItem
= NO_SELECTED_ITEM
;
3643 ROSMENUINFO MenuInfo
;
3644 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3646 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3648 /* find window that has a menu */
3650 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3651 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3652 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3654 /* check if we have to track a system menu */
3656 hTrackMenu
= GetMenu( hwnd
);
3657 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3659 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3660 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3662 wParam
|= HTSYSMENU
; /* prevent item lookup */
3665 if (!IsMenu( hTrackMenu
)) return;
3667 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3669 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3674 if( wChar
&& wChar
!= ' ' )
3676 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3677 if ( uItem
>= (UINT
)(-2) )
3679 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3680 /* schedule end of menu tracking */
3681 wFlags
|= TF_ENDMENU
;
3686 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3688 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
3690 if( uItem
== NO_SELECTED_ITEM
)
3691 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3693 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
3697 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3698 MenuExitTracking( hwnd
, FALSE
);
3701 /**********************************************************************
3702 * TrackPopupMenuEx (USER32.@)
3704 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
3705 HWND Wnd
, LPTPMPARAMS Tpm
)
3708 ROSMENUINFO MenuInfo
;
3712 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3717 if (!ValidateHwnd(Wnd
))
3719 /* invalid window see wine menu.c test_menu_trackpopupmenu line 3146 */
3723 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
3724 if (IsWindow(MenuInfo
.Wnd
))
3726 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
3730 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
3732 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3733 if (!(Flags
& TPM_NONOTIFY
))
3734 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
3736 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
3737 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
3738 Tpm
? &Tpm
->rcExclude
: NULL
);
3739 MenuExitTracking(Wnd
, TRUE
);
3743 /**********************************************************************
3744 * TrackPopupMenu (USER32.@)
3746 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
3747 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
3749 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
3754 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3755 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3757 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3759 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3760 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3761 * MFT_STRING is replaced by MIIM_STRING.
3762 * (So, I guess we should use MIIM_STRING only for strings?)
3764 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3766 * Based on wine, SetMenuItemInfo_common:
3767 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3768 * it will result in a error.
3769 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3770 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3777 LPMENUITEMINFOW mii
,
3784 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3786 if(Flags
& MF_BITMAP
)
3788 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3789 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3791 if (Flags
& MF_HELP
)
3793 /* increase ident */
3794 mii
->fType
|= MF_HELP
;
3797 else if(Flags
& MF_OWNERDRAW
)
3799 mii
->fType
|= MFT_OWNERDRAW
;
3800 mii
->fMask
|= MIIM_DATA
;
3801 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
3803 else if (Flags
& MF_SEPARATOR
)
3805 mii
->fType
|= MFT_SEPARATOR
;
3806 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3807 Flags
|= MF_GRAYED
|MF_DISABLED
;
3809 else /* Default action MF_STRING. */
3811 /* Item beginning with a backspace is a help item */
3812 if (NewItem
!= NULL
)
3816 if (*NewItem
== '\b')
3818 mii
->fType
|= MF_HELP
;
3824 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3825 if (*NewItemA
== '\b')
3827 mii
->fType
|= MF_HELP
;
3829 NewItem
= (LPCWSTR
) NewItemA
;
3833 if (Flags
& MF_HELP
)
3834 mii
->fType
|= MF_HELP
;
3835 mii
->fMask
|= MIIM_STRING
;
3836 mii
->fType
|= MFT_STRING
; /* Zero */
3837 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3839 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3841 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3845 mii
->fType
|= MFT_SEPARATOR
;
3846 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3847 Flags
|= MF_GRAYED
|MF_DISABLED
;
3851 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3853 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3856 if(Flags
& MF_MENUBREAK
)
3858 mii
->fType
|= MFT_MENUBREAK
;
3860 else if(Flags
& MF_MENUBARBREAK
)
3862 mii
->fType
|= MFT_MENUBARBREAK
;
3865 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3867 if (Flags
& MF_GRAYED
)
3868 mii
->fState
|= MF_GRAYED
;
3870 if (Flags
& MF_DISABLED
)
3871 mii
->fState
|= MF_DISABLED
;
3873 mii
->fMask
|= MIIM_STATE
;
3875 else if (Flags
& MF_HILITE
)
3877 mii
->fState
|= MF_HILITE
;
3878 mii
->fMask
|= MIIM_STATE
;
3880 else /* default state */
3882 mii
->fState
|= MFS_ENABLED
;
3883 mii
->fMask
|= MIIM_STATE
;
3886 if(Flags
& MF_POPUP
)
3888 mii
->fMask
|= MIIM_SUBMENU
;
3889 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3893 mii
->fMask
|= MIIM_ID
;
3894 mii
->wID
= (UINT
)IDNewItem
;
3900 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3902 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3905 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3907 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3908 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3909 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3910 (LPCWSTR
)&Common
->MenuName
);
3912 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3916 /* FUNCTIONS *****************************************************************/
3919 MenuIsStringItem(ULONG TypeData)
3921 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3929 AppendMenuA(HMENU hMenu
,
3931 UINT_PTR uIDNewItem
,
3934 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3943 AppendMenuW(HMENU hMenu
,
3945 UINT_PTR uIDNewItem
,
3948 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3957 CheckMenuItem(HMENU hmenu
,
3961 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3966 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3969 PROSMENUITEMINFO Items
= NULL
;
3970 UINT cChecked
, cUnchecked
;
3974 if(idFirst
> idLast
)
3977 ItemCount
= GetMenuItemCount(hMenu
);
3979 //mi.cbSize = sizeof(ROSMENUINFO);
3980 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3983 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3985 ERR("MenuGetAllRosMenuItemInfo failed\n");
3989 cChecked
= cUnchecked
= 0;
3991 for (i
= 0 ; i
< ItemCount
; i
++)
3994 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3995 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3997 if ((Items
[i
].hSubMenu
) && (uFlags
== MF_BYCOMMAND
))
3999 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
4002 if (uFlags
& MF_BYPOSITION
)
4004 if (i
< idFirst
|| i
> idLast
)
4019 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
4022 if (Items
[i
].wID
== idCheck
)
4036 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4039 Items
[i
].fType
|= MFT_RADIOCHECK
;
4040 Items
[i
].fState
|= MFS_CHECKED
;
4044 Items
[i
].fState
&= ~MFS_CHECKED
;
4047 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4049 ERR("MenuSetRosMenuItemInfo failed\n");
4054 HeapFree(GetProcessHeap(), 0, Items
);
4056 *pChecked
+= cChecked
;
4057 *pUnchecked
+= cUnchecked
;
4059 if (cChecked
|| cUnchecked
)
4069 CheckMenuRadioItem(HMENU hmenu
,
4076 UINT cUnchecked
= 0;
4077 UINT cMenuChanged
= 0;
4079 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4082 if (cMenuChanged
> 1)
4089 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4092 return (cChecked
!= 0);
4103 return NtUserxCreateMenu();
4111 CreatePopupMenu(VOID
)
4114 return NtUserxCreatePopupMenu();
4122 DrawMenuBar(HWND hWnd
)
4124 // return NtUserxDrawMenuBar(hWnd);
4125 ROSMENUINFO MenuInfo
;
4127 hMenu
= GetMenu(hWnd
);
4130 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4131 MenuInfo
.Height
= 0; // make sure to recalc size
4132 MenuSetRosMenuInfo(&MenuInfo
);
4134 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4135 SWP_NOZORDER
| SWP_FRAMECHANGED
);
4143 EnableMenuItem(HMENU hMenu
,
4147 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4157 guii
.cbSize
= sizeof(GUITHREADINFO
);
4158 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4162 guii
.hwndMenuOwner
!= top_popup
)
4164 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4168 /* if we are in the menu code, and it is active */
4169 if (!fEndMenu
&& top_popup
)
4171 /* terminate the menu handling code */
4174 /* needs to be posted to wakeup the internal menu handler */
4175 /* which will now terminate the menu, in the event that */
4176 /* the main window was minimized, or lost focus, so we */
4177 /* don't end up with an orphaned menu */
4178 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4183 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4186 ROSMENUINFO MenuInfo
;
4187 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4188 // Force bits to be set call server side....
4189 // This alone works and passes all the menu test_menu_hilitemenuitem tests.
4190 if (!NtUserHiliteMenuItem(hWnd
, hMenu
, wItemID
, wHilite
)) return FALSE
;
4191 // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
4193 if (!MenuGetRosMenuInfo(&MenuInfo
, hMenu
)) return FALSE
;
4194 if (MenuInfo
.FocusedItem
== wItemID
) return TRUE
;
4195 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4196 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4206 PWND Wnd
= ValidateHwnd(hWnd
);
4211 return UlongToHandle(Wnd
->IDMenu
);
4218 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4221 Ret
= NtUserGetMenuBarInfo( hwnd
, idObject
, idItem
, pmbi
);
4222 // Reason to move to server side!!!!!
4223 if (!Ret
) return Ret
;
4225 pmbi
->fBarFocused
= top_popup_hmenu
== pmbi
->hMenu
;
4228 pmbi
->fFocused
= pmbi
->fBarFocused
;
4239 GetMenuCheckMarkDimensions(VOID
)
4241 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4242 GetSystemMetrics(SM_CYMENUCHECK
)));
4250 GetMenuDefaultItem(HMENU hMenu
,
4254 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4262 GetMenuInfo(HMENU hmenu
,
4268 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4271 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4272 mi
.cbSize
= sizeof(MENUINFO
);
4273 mi
.fMask
= lpcmi
->fMask
;
4275 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4277 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4286 GetMenuItemCount(HMENU Menu
)
4288 ROSMENUINFO MenuInfo
;
4290 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4298 GetMenuItemID(HMENU hMenu
,
4301 ROSMENUITEMINFO mii
;
4303 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4304 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4306 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4311 if (NULL
!= mii
.hSubMenu
)
4332 LPMENUITEMINFOA mii
)
4338 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4339 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4341 SetLastError(ERROR_INVALID_PARAMETER
);
4345 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4347 /* No text requested, just pass on */
4348 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4351 AnsiBuffer
= mii
->dwTypeData
;
4352 Count
= miiW
.cch
= mii
->cch
;
4353 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4354 miiW
.dwTypeData
= 0;
4358 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4359 miiW
.cch
* sizeof(WCHAR
));
4360 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4361 miiW
.dwTypeData
[0] = 0;
4364 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4366 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4370 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4372 if (!AnsiBuffer
|| !Count
)
4374 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4375 mii
->dwTypeData
= AnsiBuffer
;
4376 mii
->cch
= miiW
.cch
;
4380 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4384 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4388 if (Count
> miiW
.cch
)
4390 AnsiBuffer
[miiW
.cch
] = 0;
4392 mii
->cch
= miiW
.cch
;
4400 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4401 mii
->dwTypeData
= AnsiBuffer
;
4415 LPMENUITEMINFOW mii
)
4421 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4422 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4424 SetLastError(ERROR_INVALID_PARAMETER
);
4428 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4430 /* No text requested, just pass on */
4431 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4434 String
= mii
->dwTypeData
;
4436 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4437 miiW
.dwTypeData
= 0;
4441 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4442 miiW
.cch
* sizeof(WCHAR
));
4443 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4444 miiW
.dwTypeData
[0] = 0;
4447 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4449 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4453 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4455 if (!String
|| !Count
)
4457 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4458 mii
->dwTypeData
= String
; // may not be zero.
4459 mii
->cch
= miiW
.cch
;
4463 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4465 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4468 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4469 mii
->dwTypeData
= String
;
4470 mii
->cch
= strlenW(String
);
4485 ROSMENUINFO MenuInfo
;
4486 ROSMENUITEMINFO mii
;
4487 memset( &mii
, 0, sizeof(mii
) );
4488 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4489 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4492 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4497 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4501 nSubItems
= MenuInfo
.MenuItemCount
;
4503 /* FIXME - ported from wine, does that work (0xff)? */
4504 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4505 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4507 return (UINT
)-1; /* Invalid submenu */
4510 /* FIXME - ported from wine, does that work? */
4511 return (mii
.fType
| mii
.fState
);
4531 memset( &mii
, 0, sizeof(mii
) );
4532 mii
.dwTypeData
= lpString
;
4533 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4534 mii
.fType
= MFT_STRING
;
4535 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4536 mii
.cch
= nMaxCount
;
4538 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4558 memset( &miiW
, 0, sizeof(miiW
) );
4559 miiW
.dwTypeData
= lpString
;
4560 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4561 miiW
.fType
= MFT_STRING
;
4562 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4563 miiW
.cch
= nMaxCount
;
4565 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4583 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4584 mi
.fMask
= MIIM_SUBMENU
;
4586 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4588 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4605 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4607 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4620 UINT_PTR uIDNewItem
,
4624 memset( &mii
, 0, sizeof(mii
) );
4625 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4626 mii
.fMask
= MIIM_FTYPE
;
4628 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4631 (LPCWSTR
) lpNewItem
,
4634 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4648 LPCMENUITEMINFOA lpmii
)
4651 UNICODE_STRING MenuText
;
4653 BOOL CleanHeap
= FALSE
;
4655 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4656 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4658 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4660 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4662 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4665 /* copy the text string */
4666 if (((mi
.fMask
& MIIM_STRING
) ||
4667 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4668 && mi
.dwTypeData
!= NULL
)
4670 if (!RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
))
4672 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
4675 mi
.dwTypeData
= MenuText
.Buffer
;
4676 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4679 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4681 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4696 LPCMENUITEMINFOW lpmii
)
4699 UNICODE_STRING MenuText
;
4702 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4703 if a bad user passes bad data, we crash his process instead of the
4706 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4707 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4709 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4711 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4713 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4716 /* copy the text string */
4717 if (((mi
.fMask
& MIIM_STRING
) ||
4718 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4719 && mi
.dwTypeData
!= NULL
)
4721 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4722 mi
.dwTypeData
= MenuText
.Buffer
;
4723 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4725 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4740 UINT_PTR uIDNewItem
,
4744 memset( &mii
, 0, sizeof(mii
) );
4745 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4746 mii
.fMask
= MIIM_FTYPE
;
4748 MenuSetItemData( &mii
,
4754 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4766 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
4775 LoadMenuA(HINSTANCE hInstance
,
4778 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4779 if (Resource
== NULL
)
4783 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4791 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4793 return(LoadMenuIndirectW(lpMenuTemplate
));
4801 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4804 WORD version
, offset
;
4805 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4807 version
= GET_WORD(p
);
4812 case 0: /* standard format is version of 0 */
4813 offset
= GET_WORD(p
);
4814 p
+= sizeof(WORD
) + offset
;
4815 if (!(hMenu
= CreateMenu())) return 0;
4816 if (!MENU_ParseResource(p
, hMenu
))
4822 case 1: /* extended format is version of 1 */
4823 offset
= GET_WORD(p
);
4824 p
+= sizeof(WORD
) + offset
;
4825 if (!(hMenu
= CreateMenu())) return 0;
4826 if (!MENUEX_ParseResource(p
, hMenu
))
4828 DestroyMenu( hMenu
);
4833 ERR("Menu template version %d not supported.\n", version
);
4843 LoadMenuW(HINSTANCE hInstance
,
4846 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4847 if (Resource
== NULL
)
4851 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4865 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4878 UINT_PTR uIDNewItem
,
4882 ROSMENUITEMINFO rmii
;
4884 memset( &mii
, 0, sizeof(mii
) );
4885 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4886 mii
.fMask
= MIIM_FTYPE
;
4888 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4892 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4894 MenuInitRosMenuItemInfo( &rmii
);
4896 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4898 if (rmii
.hSubMenu
&& (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4899 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4901 MenuCleanupRosMenuItemInfo( &rmii
);
4903 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4906 (LPCWSTR
) lpNewItem
,
4909 return SetMenuItemInfoA( hMnu
,
4911 (BOOL
)(MF_BYPOSITION
& uFlags
),
4925 UINT_PTR uIDNewItem
,
4929 ROSMENUITEMINFO rmii
;
4931 memset ( &mii
, 0, sizeof(mii
) );
4932 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4933 mii
.fMask
= MIIM_FTYPE
;
4935 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4937 mi
.Height
= 0; // Force size recalculation.
4939 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4941 MenuInitRosMenuItemInfo( &rmii
);
4943 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4945 if (rmii
.hSubMenu
&& (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4946 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4948 MenuCleanupRosMenuItemInfo( &rmii
);
4950 /* Init new data for this menu item */
4951 MenuSetItemData( &mii
,
4957 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4958 return SetMenuItemInfoW( hMnu
,
4960 (BOOL
)(MF_BYPOSITION
& uFlags
),
4972 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4988 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4990 SetLastError(ERROR_INVALID_PARAMETER
);
4994 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4995 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
5008 HBITMAP hBitmapUnchecked
,
5009 HBITMAP hBitmapChecked
)
5011 ROSMENUITEMINFO uItem
;
5012 memset ( &uItem
, 0, sizeof(uItem
) );
5013 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
5015 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
5016 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
5018 if (!hBitmapChecked
&& !hBitmapUnchecked
)
5020 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
5022 else /* Install new bitmaps */
5024 uItem
.hbmpChecked
= hBitmapChecked
;
5025 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5026 uItem
.fState
|= MF_USECHECKBITMAPS
;
5028 return NtUserMenuItemInfo(hMenu
, uPosition
,
5029 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
5042 LPCMENUITEMINFOA lpmii
)
5044 MENUITEMINFOW MenuItemInfoW
;
5045 UNICODE_STRING UnicodeString
;
5046 ULONG Result
= FALSE
;
5048 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5050 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5052 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5053 MenuItemInfoW
.hbmpItem
= NULL
;
5056 * MIIM_STRING == good
5057 * MIIM_TYPE & MFT_STRING == good
5058 * MIIM_STRING & MFT_STRING == good
5059 * MIIM_STRING & MFT_OWNERSRAW == good
5061 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5062 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5063 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5064 && MenuItemInfoW
.dwTypeData
!= NULL
)
5066 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5067 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5068 (LPSTR
)MenuItemInfoW
.dwTypeData
))
5070 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5073 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5074 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5078 UnicodeString
.Buffer
= NULL
;
5081 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5082 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5084 if (UnicodeString
.Buffer
!= NULL
)
5086 RtlFreeUnicodeString(&UnicodeString
);
5102 LPCMENUITEMINFOW lpmii
)
5104 MENUITEMINFOW MenuItemInfoW
;
5107 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5109 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5111 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5112 MenuItemInfoW
.hbmpItem
= NULL
;
5115 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5116 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5117 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5118 && MenuItemInfoW
.dwTypeData
!= NULL
)
5120 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5122 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5123 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5139 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5144 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5147 return NtUserSetSystemMenu(hwnd
, hMenu
);
5151 // Example for the Win32/User32 rewrite.
5152 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5166 return NtUserTrackPopupMenuEx( Menu
,
5171 NULL
); // LPTPMPARAMS is null
5180 GetMenuContextHelpId(HMENU hmenu
)
5183 mi
.cbSize
= sizeof(ROSMENUINFO
);
5184 mi
.fMask
= MIM_HELPID
;
5186 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5188 return mi
.dwContextHelpID
;
5209 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5212 Result
= (ULONG_PTR
)lResult
;
5217 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5237 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5240 Result
= (ULONG_PTR
)lResult
;
5245 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5256 LPCWSTR lpszNewItem
,
5261 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5262 for MF_DELETE. We should check the parameters for all others
5263 MF_* actions also (anybody got a doc on ChangeMenu?).
5266 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5269 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5272 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5275 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5278 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5279 flags
&~ MF_REMOVE
);
5281 default : /* MF_INSERT */
5282 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5299 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5300 for MF_DELETE. We should check the parameters for all others
5301 MF_* actions also (anybody got a doc on ChangeMenu?).
5304 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5307 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5310 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5313 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5316 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5317 flags
&~ MF_REMOVE
);
5319 default : /* MF_INSERT */
5320 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);