2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: win32ss/user/ntuser/menu.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
10 DBG_DEFAULT_CHANNEL(UserMenu
);
12 /* INTERNAL ******************************************************************/
14 HFONT ghMenuFont
= NULL
;
15 HFONT ghMenuFontBold
= NULL
;
16 static SIZE MenuCharSize
;
18 /* Use global popup window because there's no way 2 menus can
19 * be tracked at the same time. */
20 static HWND top_popup
= NULL
;
21 static HMENU top_popup_hmenu
= NULL
;
23 BOOL fInsideMenuLoop
= FALSE
;
24 BOOL fInEndMenu
= FALSE
;
26 /* internal popup menu window messages */
28 #define MM_SETMENUHANDLE (WM_USER + 0)
29 #define MM_GETMENUHANDLE (WM_USER + 1)
31 /* internal flags for menu tracking */
33 #define TF_ENDMENU 0x10000
34 #define TF_SUSPENDPOPUP 0x20000
35 #define TF_SKIPREMOVE 0x40000
38 /* maximum allowed depth of any branch in the menu tree.
39 * This value is slightly larger than in windows (25) to
40 * stay on the safe side. */
41 #define MAXMENUDEPTH 30
43 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
45 #define MENUITEMINFO_TYPE_MASK \
46 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
47 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
48 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
50 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
52 #define STATE_MASK (~TYPE_MASK)
54 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
56 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
58 #define IS_SYSTEM_MENU(MenuInfo) \
59 (!((MenuInfo)->fFlags & MNF_POPUP) && ((MenuInfo)->fFlags & MNF_SYSMENU))
61 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
63 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
64 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
66 /* Maximum number of menu items a menu can contain */
67 #define MAX_MENU_ITEMS (0x4000)
68 #define MAX_GOINTOSUBMENU (0x10)
70 /* Space between 2 columns */
71 #define MENU_COL_SPACE 4
73 #define MENU_ITEM_HBMP_SPACE (5)
74 #define MENU_BAR_ITEMS_SPACE (12)
75 #define SEPARATOR_HEIGHT (5)
76 #define MENU_TAB_SPACE (8)
81 PMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
82 PMENU TopMenu
; /* initial menu */
83 PWND OwnerWnd
; /* where notifications are sent */
87 /* Internal MenuTrackMenu() flags */
88 #define TPM_INTERNAL 0xF0000000
89 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
90 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
95 #define UpdateMenuItemState(state, change) \
97 if((change) & MF_GRAYED) { \
98 (state) |= MF_GRAYED; \
100 (state) &= ~MF_GRAYED; \
101 } /* Separate the two for test_menu_resource_layout.*/ \
102 if((change) & MF_DISABLED) { \
103 (state) |= MF_DISABLED; \
105 (state) &= ~MF_DISABLED; \
107 if((change) & MFS_CHECKED) { \
108 (state) |= MFS_CHECKED; \
110 (state) &= ~MFS_CHECKED; \
112 if((change) & MFS_HILITE) { \
113 (state) |= MFS_HILITE; \
115 (state) &= ~MFS_HILITE; \
117 if((change) & MFS_DEFAULT) { \
118 (state) |= MFS_DEFAULT; \
120 (state) &= ~MFS_DEFAULT; \
122 if((change) & MF_MOUSESELECT) { \
123 (state) |= MF_MOUSESELECT; \
125 (state) &= ~MF_MOUSESELECT; \
131 DumpMenuItemList(PMENU Menu
, PITEM MenuItem
)
133 UINT cnt
= 0, i
= Menu
->cItems
;
136 if(MenuItem
->lpstr
.Length
)
137 DbgPrint(" %d. %wZ\n", ++cnt
, &MenuItem
->lpstr
);
139 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt
, (DWORD
)MenuItem
->lpstr
.Buffer
);
141 if(MFT_BITMAP
& MenuItem
->fType
)
142 DbgPrint("MFT_BITMAP ");
143 if(MFT_MENUBARBREAK
& MenuItem
->fType
)
144 DbgPrint("MFT_MENUBARBREAK ");
145 if(MFT_MENUBREAK
& MenuItem
->fType
)
146 DbgPrint("MFT_MENUBREAK ");
147 if(MFT_OWNERDRAW
& MenuItem
->fType
)
148 DbgPrint("MFT_OWNERDRAW ");
149 if(MFT_RADIOCHECK
& MenuItem
->fType
)
150 DbgPrint("MFT_RADIOCHECK ");
151 if(MFT_RIGHTJUSTIFY
& MenuItem
->fType
)
152 DbgPrint("MFT_RIGHTJUSTIFY ");
153 if(MFT_SEPARATOR
& MenuItem
->fType
)
154 DbgPrint("MFT_SEPARATOR ");
155 if(MFT_STRING
& MenuItem
->fType
)
156 DbgPrint("MFT_STRING ");
157 DbgPrint("\n fState=");
158 if(MFS_DISABLED
& MenuItem
->fState
)
159 DbgPrint("MFS_DISABLED ");
161 DbgPrint("MFS_ENABLED ");
162 if(MFS_CHECKED
& MenuItem
->fState
)
163 DbgPrint("MFS_CHECKED ");
165 DbgPrint("MFS_UNCHECKED ");
166 if(MFS_HILITE
& MenuItem
->fState
)
167 DbgPrint("MFS_HILITE ");
169 DbgPrint("MFS_UNHILITE ");
170 if(MFS_DEFAULT
& MenuItem
->fState
)
171 DbgPrint("MFS_DEFAULT ");
172 if(MFS_GRAYED
& MenuItem
->fState
)
173 DbgPrint("MFS_GRAYED ");
174 DbgPrint("\n wId=%d\n", MenuItem
->wID
);
178 DbgPrint("Entries: %d\n", cnt
);
183 #define FreeMenuText(Menu,MenuItem) \
185 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
186 (MenuItem)->lpstr.Length) { \
187 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
192 IntGetMenuObject(HMENU hMenu
)
194 PMENU Menu
= UserGetMenuObject(hMenu
);
196 Menu
->head
.cLockObj
++;
201 PMENU FASTCALL
VerifyMenu(PMENU pMenu
)
207 if (!pMenu
) return NULL
;
209 Error
= EngGetLastError();
213 hMenu
= UserHMGetHandle(pMenu
);
214 pItem
= pMenu
->rgItems
;
221 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
223 ERR("Run away LOOP!\n");
224 EngSetLastError(Error
);
225 _SEH2_YIELD(return NULL
);
229 if ( UserObjectInDestroy(hMenu
))
231 ERR("Menu is marked for destruction!\n");
234 EngSetLastError(Error
);
240 IntIsMenu(HMENU Menu
)
242 if (UserGetMenuObject(Menu
)) return TRUE
;
248 IntGetMenu(HWND hWnd
)
250 PWND Wnd
= ValidateHwndNoErr(hWnd
);
255 return UserGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
258 PMENU
get_win_sys_menu( HWND hwnd
)
261 WND
*win
= ValidateHwndNoErr( hwnd
);
264 ret
= UserGetMenuObject(win
->SystemMenu
);
269 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
)
273 ASSERT(UserIsEnteredExclusive());
274 if (pMenu
->rgItems
) /* recursively destroy submenus */
277 ITEM
*item
= pMenu
->rgItems
;
278 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
280 SubMenu
= item
->spSubMenu
;
281 item
->spSubMenu
= NULL
;
283 /* Remove Item Text */
284 FreeMenuText(pMenu
,item
);
286 /* Remove Item Bitmap and set it for this process */
287 if (item
->hbmp
&& !(item
->fState
& MFS_HBMMENUBMP
))
289 GreSetObjectOwner(item
->hbmp
, GDI_OBJ_HMGR_POWNED
);
293 /* Remove Item submenu */
294 if (bRecurse
&& SubMenu
)//VerifyMenu(SubMenu))
296 /* Release submenu since it was referenced when inserted */
297 IntReleaseMenuObject(SubMenu
);
298 IntDestroyMenuObject(SubMenu
, bRecurse
);
302 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
303 pMenu
->rgItems
= NULL
;
309 /* Callback for the object manager */
311 UserDestroyMenuObject(PVOID Object
)
313 return IntDestroyMenuObject(Object
, TRUE
);
317 IntDestroyMenuObject(PMENU Menu
, BOOL bRecurse
)
319 ASSERT(UserIsEnteredExclusive());
324 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
329 Window
= ValidateHwndNoErr(Menu
->hWnd
);
332 //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
334 /* DestroyMenu should not destroy system menu popup owner */
335 if ((Menu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
)
337 // Should we check it to see if it has Class?
338 ERR("FIXME Pop up menu window thing'ie\n");
339 //co_UserDestroyWindow( Window );
345 if (!UserMarkObjectDestroy(Menu
)) return TRUE
;
347 /* Remove all menu items */
348 IntDestroyMenu( Menu
, bRecurse
);
350 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
351 TRACE("IntDestroyMenuObject %d\n",ret
);
361 NONCLIENTMETRICSW ncm
;
363 /* get the menu font */
364 if (!ghMenuFont
|| !ghMenuFontBold
)
366 ncm
.cbSize
= sizeof(ncm
);
367 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
369 ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
373 ghMenuFont
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
374 if (ghMenuFont
== NULL
)
376 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
379 ncm
.lfMenuFont
.lfWeight
= min(ncm
.lfMenuFont
.lfWeight
+ (FW_BOLD
- FW_NORMAL
), FW_HEAVY
);
380 ghMenuFontBold
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
381 if (ghMenuFontBold
== NULL
)
383 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
384 GreDeleteObject(ghMenuFont
);
389 GreSetObjectOwner(ghMenuFont
, GDI_OBJ_HMGR_PUBLIC
);
390 GreSetObjectOwner(ghMenuFontBold
, GDI_OBJ_HMGR_PUBLIC
);
399 /**********************************************************************
402 * detect if there are loops in the menu tree (or the depth is too large)
404 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
410 if (!pmenu
) return depth
;
413 if( depth
> MAXMENUDEPTH
) return depth
;
414 item
= pmenu
->rgItems
;
416 for( i
= 0; i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
418 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
420 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
421 if( bdepth
> subdepth
) subdepth
= bdepth
;
423 if( subdepth
> MAXMENUDEPTH
)
424 TRACE("<- hmenu %p\n", item
->spSubMenu
);
430 /******************************************************************************
432 * UINT MenuGetStartOfNextColumn(
435 *****************************************************************************/
437 static UINT
MENU_GetStartOfNextColumn(
444 return NO_SELECTED_ITEM
;
447 if( i
== NO_SELECTED_ITEM
)
450 pItem
= menu
->rgItems
;
451 if (!pItem
) return NO_SELECTED_ITEM
;
453 for( ; i
< menu
->cItems
; ++i
) {
454 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
458 return NO_SELECTED_ITEM
;
461 /******************************************************************************
463 * UINT MenuGetStartOfPrevColumn(
466 *****************************************************************************/
467 static UINT
MENU_GetStartOfPrevColumn(
474 return NO_SELECTED_ITEM
;
476 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
477 return NO_SELECTED_ITEM
;
479 pItem
= menu
->rgItems
;
480 if (!pItem
) return NO_SELECTED_ITEM
;
482 /* Find the start of the column */
484 for(i
= menu
->iItem
; i
!= 0 &&
485 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
489 return NO_SELECTED_ITEM
;
491 for(--i
; i
!= 0; --i
) {
492 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
496 TRACE("ret %d.\n", i
);
501 /***********************************************************************
504 * Find a menu item. Return a pointer on the item, and modifies *hmenu
505 * in case the item was in a sub-menu.
507 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
510 ITEM
*fallback
= NULL
;
511 UINT fallback_pos
= 0;
514 if (!menu
) return NULL
;
516 if (wFlags
& MF_BYPOSITION
)
518 if (!menu
->cItems
) return NULL
;
519 if (*nPos
>= menu
->cItems
) return NULL
;
520 return &menu
->rgItems
[*nPos
];
524 PITEM item
= menu
->rgItems
;
525 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
529 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
530 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
536 else if (item
->wID
== *nPos
)
538 /* fallback to this item if nothing else found */
543 else if (item
->wID
== *nPos
)
552 *nPos
= fallback_pos
;
557 /***********************************************************************
560 * Find a Sub menu. Return the position of the submenu, and modifies
561 * *hmenu in case it is found in another sub-menu.
562 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
564 static UINT FASTCALL
MENU_FindSubMenu(PMENU
*menu
, PMENU SubTarget
)
569 item
= ((PMENU
)*menu
)->rgItems
;
570 for (i
= 0; i
< ((PMENU
)*menu
)->cItems
; i
++, item
++)
572 if (!item
->spSubMenu
)
576 if (item
->spSubMenu
== SubTarget
)
582 PMENU pSubMenu
= item
->spSubMenu
;
583 UINT pos
= MENU_FindSubMenu( &pSubMenu
, SubTarget
);
584 if (pos
!= NO_SELECTED_ITEM
)
592 return NO_SELECTED_ITEM
;
596 IntRemoveMenuItem( PMENU pMenu
, UINT nPos
, UINT wFlags
, BOOL bRecurse
)
601 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
602 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
606 FreeMenuText(pMenu
,item
);
607 if (bRecurse
&& item
->spSubMenu
)
609 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
);
611 ////// Use cAlloced with inc's of 8's....
612 if (--pMenu
->cItems
== 0)
614 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
615 pMenu
->rgItems
= NULL
;
619 while (nPos
< pMenu
->cItems
)
625 newItems
= DesktopHeapReAlloc(pMenu
->head
.rpdesk
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
628 pMenu
->rgItems
= newItems
;
634 /**********************************************************************
637 * Insert (allocate) a new item into a menu.
639 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
643 /* Find where to insert new item */
645 if (flags
& MF_BYPOSITION
) {
646 if (pos
> menu
->cItems
)
649 if (!MENU_FindItem( &menu
, &pos
, flags
))
651 if (submenu
) *submenu
= menu
;
652 if (npos
) *npos
= pos
;
657 /* Make sure that MDI system buttons stay on the right side.
658 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
659 * regardless of their id.
662 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
663 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
666 TRACE("inserting at %u flags %x\n", pos
, flags
);
668 /* Create new items array */
670 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
673 WARN("allocation failed\n" );
676 if (menu
->cItems
> 0)
678 /* Copy the old array into the new one */
679 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
680 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
681 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
683 menu
->rgItems
= newItems
;
685 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
686 menu
->cyMenu
= 0; /* force size recalculate */
687 return &newItems
[pos
];
692 _In_ PMENU MenuObject
,
695 PROSMENUITEMINFO ItemInfo
,
696 PUNICODE_STRING lpstr
)
699 PMENU SubMenu
= NULL
;
701 NT_ASSERT(MenuObject
!= NULL
);
703 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
705 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
709 SubMenu
= MenuObject
;
711 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
713 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
715 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
719 /* Force size recalculation! */
721 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
723 TRACE("IntInsertMenuItemToList = %u %i\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
730 _Out_ PHANDLE Handle
,
732 _In_ PDESKTOP Desktop
,
733 _In_ PPROCESSINFO ppi
)
737 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
749 Menu
->cyMax
= 0; /* Default */
750 Menu
->hbrBack
= NULL
; /* No brush */
751 Menu
->dwContextHelpId
= 0; /* Default */
752 Menu
->dwMenuData
= 0; /* Default */
753 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
754 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
755 Menu
->spwndNotify
= NULL
;
756 Menu
->cyMenu
= 0; // Height
757 Menu
->cxMenu
= 0; // Width
758 Menu
->cItems
= 0; // Item count
761 Menu
->cxTextAlign
= 0;
762 Menu
->rgItems
= NULL
;
765 Menu
->TimeToHide
= FALSE
;
771 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
773 PITEM MenuItem
, NewMenuItem
= NULL
;
779 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, Source
->cItems
* sizeof(ITEM
));
780 if(!NewMenuItem
) return FALSE
;
782 RtlZeroMemory(NewMenuItem
, Source
->cItems
* sizeof(ITEM
));
784 Destination
->rgItems
= NewMenuItem
;
786 MenuItem
= Source
->rgItems
;
787 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
789 NewMenuItem
->fType
= MenuItem
->fType
;
790 NewMenuItem
->fState
= MenuItem
->fState
;
791 NewMenuItem
->wID
= MenuItem
->wID
;
792 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
793 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
794 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
795 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
796 if (MenuItem
->lpstr
.Length
)
798 NewMenuItem
->lpstr
.Length
= 0;
799 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
800 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
801 if (!NewMenuItem
->lpstr
.Buffer
)
803 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
806 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
807 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
808 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
812 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
813 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
815 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
816 Destination
->cItems
= i
+ 1;
822 IntCloneMenu(PMENU Source
)
830 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
831 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
833 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
840 Menu
->fFlags
= Source
->fFlags
;
841 Menu
->cyMax
= Source
->cyMax
;
842 Menu
->hbrBack
= Source
->hbrBack
;
843 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
844 Menu
->dwMenuData
= Source
->dwMenuData
;
845 Menu
->iItem
= NO_SELECTED_ITEM
;
846 Menu
->spwndNotify
= NULL
;
852 Menu
->cxTextAlign
= 0;
853 Menu
->rgItems
= NULL
;
856 Menu
->TimeToHide
= FALSE
;
858 IntCloneMenuItems(Menu
, Source
);
864 IntSetMenuFlagRtoL(PMENU Menu
)
866 ERR("SetMenuFlagRtoL\n");
867 Menu
->fFlags
|= MNF_RTOL
;
872 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
874 Menu
->dwContextHelpId
= dwContextHelpId
;
879 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
881 if(lpmi
->fMask
& MIM_BACKGROUND
)
882 lpmi
->hbrBack
= Menu
->hbrBack
;
883 if(lpmi
->fMask
& MIM_HELPID
)
884 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
885 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
886 lpmi
->cyMax
= Menu
->cyMax
;
887 if(lpmi
->fMask
& MIM_MENUDATA
)
888 lpmi
->dwMenuData
= Menu
->dwMenuData
;
889 if(lpmi
->fMask
& MIM_STYLE
)
890 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
892 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
894 lpmi
->cItems
= Menu
->cItems
;
896 lpmi
->iItem
= Menu
->iItem
;
897 lpmi
->cxMenu
= Menu
->cxMenu
;
898 lpmi
->cyMenu
= Menu
->cyMenu
;
899 lpmi
->spwndNotify
= Menu
->spwndNotify
;
900 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
901 lpmi
->iTop
= Menu
->iTop
;
902 lpmi
->iMaxTop
= Menu
->iMaxTop
;
903 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
905 lpmi
->fFlags
= Menu
->fFlags
;
906 lpmi
->Self
= Menu
->head
.h
;
907 lpmi
->TimeToHide
= Menu
->TimeToHide
;
908 lpmi
->Wnd
= Menu
->hWnd
;
914 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
916 if(lpmi
->fMask
& MIM_BACKGROUND
)
917 Menu
->hbrBack
= lpmi
->hbrBack
;
918 if(lpmi
->fMask
& MIM_HELPID
)
919 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
920 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
921 Menu
->cyMax
= lpmi
->cyMax
;
922 if(lpmi
->fMask
& MIM_MENUDATA
)
923 Menu
->dwMenuData
= lpmi
->dwMenuData
;
924 if(lpmi
->fMask
& MIM_STYLE
)
925 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
926 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
929 PITEM item
= Menu
->rgItems
;
930 for ( i
= Menu
->cItems
; i
; i
--, item
++)
932 if ( item
->spSubMenu
)
934 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
938 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
940 Menu
->iItem
= lpmi
->iItem
;
941 Menu
->cyMenu
= lpmi
->cyMenu
;
942 Menu
->cxMenu
= lpmi
->cxMenu
;
943 Menu
->spwndNotify
= lpmi
->spwndNotify
;
944 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
945 Menu
->iTop
= lpmi
->iTop
;
946 Menu
->iMaxTop
= lpmi
->iMaxTop
;
947 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
949 Menu
->TimeToHide
= lpmi
->TimeToHide
;
950 Menu
->hWnd
= lpmi
->Wnd
;
952 if ( lpmi
->fMask
& MIM_STYLE
)
954 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
955 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
956 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
962 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
963 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
967 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
969 lpmii
->fType
= MenuItem
->fType
;
971 if(lpmii
->fMask
& MIIM_BITMAP
)
973 lpmii
->hbmpItem
= MenuItem
->hbmp
;
975 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
977 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
978 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
980 if(lpmii
->fMask
& MIIM_DATA
)
982 lpmii
->dwItemData
= MenuItem
->dwItemData
;
984 if(lpmii
->fMask
& MIIM_ID
)
986 lpmii
->wID
= MenuItem
->wID
;
988 if(lpmii
->fMask
& MIIM_STATE
)
990 lpmii
->fState
= MenuItem
->fState
;
992 if(lpmii
->fMask
& MIIM_SUBMENU
)
994 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
997 if ((lpmii
->fMask
& MIIM_STRING
) ||
998 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1000 if (lpmii
->dwTypeData
== NULL
)
1002 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1005 { //// lpmii->lpstr can be read in user mode!!!!
1006 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1007 min(lpmii
->cch
* sizeof(WCHAR
),
1008 MenuItem
->lpstr
.MaximumLength
));
1009 if (! NT_SUCCESS(Status
))
1011 SetLastNtError(Status
);
1017 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1019 lpmii
->Rect
.left
= MenuItem
->xItem
;
1020 lpmii
->Rect
.top
= MenuItem
->yItem
;
1021 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1022 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1023 lpmii
->dxTab
= MenuItem
->dxTab
;
1024 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1025 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1026 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1033 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1035 PMENU SubMenuObject
;
1036 BOOL circref
= FALSE
;
1038 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1042 if ( lpmii
->fMask
& MIIM_FTYPE
)
1044 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1045 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1047 if (lpmii
->fMask
& MIIM_TYPE
)
1049 #if 0 //// Done in User32.
1050 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1052 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1053 KeRosDumpStackFrames(NULL
, 20);
1054 /* This does not happen on Win9x/ME */
1055 SetLastNtError( ERROR_INVALID_PARAMETER
);
1060 * Delete the menu item type when changing type from
1063 if (MenuItem
->fType
!= lpmii
->fType
&&
1064 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1066 FreeMenuText(MenuObject
,MenuItem
);
1067 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1068 MenuItem
->Xlpstr
= NULL
;
1070 if(lpmii
->fType
& MFT_BITMAP
)
1073 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1075 { /* Win 9x/Me stuff */
1076 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1078 lpmii
->dwTypeData
= 0;
1081 if(lpmii
->fMask
& MIIM_BITMAP
)
1083 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1084 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1085 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1087 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1089 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1091 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1092 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1094 if(lpmii
->fMask
& MIIM_DATA
)
1096 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1098 if(lpmii
->fMask
& MIIM_ID
)
1100 MenuItem
->wID
= lpmii
->wID
;
1102 if(lpmii
->fMask
& MIIM_STATE
)
1104 /* Remove MFS_DEFAULT flag from all other menu items if this item
1105 has the MFS_DEFAULT state */
1106 if(lpmii
->fState
& MFS_DEFAULT
)
1107 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1108 /* Update the menu item state flags */
1109 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1112 if(lpmii
->fMask
& MIIM_SUBMENU
)
1114 if (lpmii
->hSubMenu
)
1116 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1117 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1119 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1121 if (MenuObject
== SubMenuObject
)
1124 ERR("Pop Up Menu Double Trouble!\n");
1125 SubMenuObject
= IntCreateMenu(&hMenu
,
1127 MenuObject
->head
.rpdesk
,
1128 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1129 if (!SubMenuObject
) return FALSE
;
1130 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1133 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1135 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1136 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1139 /* Make sure the submenu is marked as a popup menu */
1140 SubMenuObject
->fFlags
|= MNF_POPUP
;
1141 // Now fix the test_subpopup_locked_by_menu tests....
1142 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1143 MenuItem
->spSubMenu
= SubMenuObject
;
1144 UserReferenceObject(SubMenuObject
);
1148 EngSetLastError( ERROR_INVALID_PARAMETER
);
1153 { // If submenu just dereference it.
1154 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1155 MenuItem
->spSubMenu
= NULL
;
1159 if ((lpmii
->fMask
& MIIM_STRING
) ||
1160 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1162 /* free the string when used */
1163 FreeMenuText(MenuObject
,MenuItem
);
1164 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1165 MenuItem
->Xlpstr
= NULL
;
1167 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1169 UNICODE_STRING Source
;
1171 if (!NT_VERIFY(lpmii
->cch
<= UNICODE_STRING_MAX_CHARS
))
1176 Source
.Length
= Source
.MaximumLength
= (USHORT
)(lpmii
->cch
* sizeof(WCHAR
));
1177 Source
.Buffer
= lpmii
->dwTypeData
;
1179 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1180 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1182 MenuItem
->lpstr
.Length
= 0;
1183 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1184 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1185 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1187 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1188 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1193 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1194 !MenuItem
->Xlpstr
&&
1195 !lpmii
->dwTypeData
&&
1196 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1198 MenuItem
->fType
|= MFT_SEPARATOR
;
1200 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1202 MenuItem
->xItem
= lpmii
->Rect
.left
;
1203 MenuItem
->yItem
= lpmii
->Rect
.top
;
1204 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1205 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1206 MenuItem
->dxTab
= lpmii
->dxTab
;
1207 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1208 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1209 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1217 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1222 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1224 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1226 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1228 /* If the close item in the system menu change update the close button */
1231 switch (MenuItem
->wID
) // More than just close.
1239 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1241 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1243 /* Refresh the frame to reflect the change */
1244 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1246 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1249 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1259 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1264 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1266 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1268 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1274 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1277 PITEM MenuItem
= MenuObject
->rgItems
;
1279 if (!MenuItem
) return FALSE
;
1281 /* reset all default-item flags */
1282 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1284 MenuItem
->fState
&= ~MFS_DEFAULT
;
1287 /* no default item */
1288 if(uItem
== (UINT
)-1)
1292 MenuItem
= MenuObject
->rgItems
;
1295 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1296 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1301 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1303 if (MenuItem
->wID
== uItem
)
1305 MenuItem
->fState
|= MFS_DEFAULT
;
1315 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1318 PITEM MenuItem
= MenuObject
->rgItems
;
1321 if (!MenuItem
) return -1;
1323 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1326 if (i
>= MenuObject
->cItems
) return -1;
1329 /* default: don't return disabled items */
1330 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1332 /* search rekursiv when needed */
1333 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1337 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1339 if ( -1 != ret
) return ret
;
1341 /* when item not found in submenu, return the popup item */
1343 return ( fByPos
) ? i
: MenuItem
->wID
;
1353 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1354 return pItem
->spSubMenu
;
1357 /***********************************************************************
1358 * MenuInitSysMenuPopup
1360 * Grey the appropriate items in System menu.
1362 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1367 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1368 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1369 gray
= ((style
& WS_MAXIMIZE
) != 0);
1370 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1371 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1372 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1373 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1374 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1375 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1376 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1377 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1379 /* The menu item must keep its state if it's disabled */
1381 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1383 /* Set default menu item */
1384 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1385 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1386 else DefItem
= SC_CLOSE
;
1388 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1392 /***********************************************************************
1393 * MenuDrawPopupGlyph
1395 * Draws popup magic glyphs (can be found in system menu).
1397 static void FASTCALL
1398 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1401 HFONT hFont
, hOldFont
;
1407 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1410 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1413 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1416 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1420 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1423 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1424 RECTL_vInflateRect(r
, -2, -2);
1425 lf
.lfHeight
= r
->bottom
- r
->top
;
1427 lf
.lfWeight
= FW_NORMAL
;
1428 lf
.lfCharSet
= DEFAULT_CHARSET
;
1429 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1430 hFont
= GreCreateFontIndirectW(&lf
);
1431 /* save font and text color */
1432 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1433 clrsave
= GreGetTextColor(dc
);
1434 bkmode
= GreGetBkMode(dc
);
1435 /* set color and drawing mode */
1436 IntGdiSetBkMode(dc
, TRANSPARENT
);
1442 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1443 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1446 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1447 /* draw selected symbol */
1448 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1449 /* restore previous settings */
1450 IntGdiSetTextColor(dc
, clrsave
);
1451 NtGdiSelectFont(dc
, hOldFont
);
1452 IntGdiSetBkMode(dc
, bkmode
);
1453 GreDeleteObject(hFont
);
1456 /***********************************************************************
1457 * MENU_AdjustMenuItemRect
1459 * Adjust menu item rectangle according to scrolling state.
1462 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1464 if (menu
->dwArrowsOn
)
1466 UINT arrow_bitmap_height
;
1467 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1468 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1469 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1473 /***********************************************************************
1474 * MENU_FindItemByCoords
1476 * Find the item at the specified coordinates (screen coords). Does
1477 * not work for child windows and therefore should not be called for
1478 * an arbitrary system menu.
1480 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1486 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1488 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1490 cx
= UserGetSystemMetrics(SM_CXDLGFRAME
);
1491 cy
= UserGetSystemMetrics(SM_CYDLGFRAME
);
1492 RECTL_vInflateRect(&rect
, -cx
, -cy
);
1494 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1495 pt
.x
= rect
.right
- 1 - pt
.x
;
1499 item
= menu
->rgItems
;
1500 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1502 //rect = item->rect;
1503 rect
.left
= item
->xItem
;
1504 rect
.top
= item
->yItem
;
1505 rect
.right
= item
->cxItem
; // Do this for now......
1506 rect
.bottom
= item
->cyItem
;
1508 MENU_AdjustMenuItemRect(menu
, &rect
);
1509 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1518 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1520 MENU
*menu
= UserGetMenuObject(hMenu
);
1523 /*FIXME: Do we have to handle hWnd here? */
1524 if (!menu
) return -1;
1525 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1529 /***********************************************************************
1532 * Find the menu item selected by a key press.
1533 * Return item id, -1 if none, -2 if we should close the menu.
1535 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1536 WCHAR Key
, BOOL ForceMenuChar
)
1541 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1543 if (!menu
|| !VerifyMenu(menu
))
1544 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1547 ITEM
*item
= menu
->rgItems
;
1549 if ( !ForceMenuChar
)
1552 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1554 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1556 LPWSTR text
= item
->Xlpstr
;
1559 const WCHAR
*p
= text
- 2;
1562 const WCHAR
*q
= p
+ 2;
1563 p
= wcschr (q
, '&');
1564 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1566 while (p
!= NULL
&& p
[1] == '&');
1567 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1572 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1573 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1575 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1576 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1577 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1578 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1583 /***********************************************************************
1584 * MenuGetBitmapItemSize
1586 * Get the size of a bitmap item.
1588 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1591 HBITMAP bmp
= lpitem
->hbmp
;
1593 size
->cx
= size
->cy
= 0;
1595 /* check if there is a magic menu item associated with this item */
1596 if (IS_MAGIC_BITMAP(bmp
))
1598 switch((INT_PTR
) bmp
)
1600 case (INT_PTR
)HBMMENU_CALLBACK
:
1602 MEASUREITEMSTRUCT measItem
;
1603 measItem
.CtlType
= ODT_MENU
;
1605 measItem
.itemID
= lpitem
->wID
;
1606 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1607 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1608 measItem
.itemData
= lpitem
->dwItemData
;
1609 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1610 size
->cx
= measItem
.itemWidth
;
1611 size
->cy
= measItem
.itemHeight
;
1612 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1617 case (INT_PTR
) HBMMENU_SYSTEM
:
1618 if (lpitem
->dwItemData
)
1620 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1624 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1625 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1626 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1627 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1628 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1629 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1630 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1631 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1632 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1633 /* FIXME: Why we need to subtract these magic values? */
1634 /* to make them smaller than the menu bar? */
1635 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1636 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1641 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1643 size
->cx
= bm
.bmWidth
;
1644 size
->cy
= bm
.bmHeight
;
1648 /***********************************************************************
1649 * MenuDrawBitmapItem
1651 * Draw a bitmap item.
1653 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1654 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1660 int w
= rect
->right
- rect
->left
;
1661 int h
= rect
->bottom
- rect
->top
;
1662 int bmp_xoffset
= 0;
1665 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1668 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1670 /* Check if there is a magic menu item associated with this item */
1671 if (IS_MAGIC_BITMAP(hbmToDraw
))
1677 switch ((INT_PTR
)hbmToDraw
)
1679 case (INT_PTR
)HBMMENU_SYSTEM
:
1680 if (lpitem
->dwItemData
)
1682 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1684 ERR("Get Item Data from this Window!!!\n");
1687 ERR("Draw Bitmap\n");
1688 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1689 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1693 PCURICON_OBJECT pIcon
= NULL
;
1694 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1696 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1697 /* only use right half of the bitmap */
1698 //bmp_xoffset = bm.bmWidth / 2;
1699 //bm.bmWidth -= bmp_xoffset;
1702 pIcon
= NC_IconForWindow(WndOwner
);
1703 // FIXME: NC_IconForWindow should reference it for us */
1704 if (pIcon
) UserReferenceObject(pIcon
);
1709 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1710 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1711 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1712 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1713 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1714 UserDereferenceObject(pIcon
);
1719 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1720 flags
= DFCS_CAPTIONRESTORE
;
1722 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1724 flags
= DFCS_CAPTIONMIN
;
1726 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1728 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1730 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1731 flags
= DFCS_CAPTIONCLOSE
;
1733 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1734 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1736 case (INT_PTR
)HBMMENU_CALLBACK
:
1738 DRAWITEMSTRUCT drawItem
;
1740 drawItem
.CtlType
= ODT_MENU
;
1742 drawItem
.itemID
= lpitem
->wID
;
1743 drawItem
.itemAction
= odaction
;
1744 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1745 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1746 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1747 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1748 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1749 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1750 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1751 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1753 drawItem
.rcItem
= *rect
;
1754 drawItem
.itemData
= lpitem
->dwItemData
;
1755 /* some applications make this assumption on the DC's origin */
1756 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1757 RECTL_vOffsetRect(&drawItem
.rcItem
, -(LONG
)lpitem
->xItem
, -(LONG
)lpitem
->yItem
);
1758 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1759 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1764 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1765 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1766 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1767 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1768 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1771 RECTL_vInflateRect(&r
, -1, -1);
1772 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1773 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1777 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1780 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1781 NtGdiSelectBitmap( hdcMem
, bmp
);
1782 /* handle fontsize > bitmap_height */
1783 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1785 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1786 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1787 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1790 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
1795 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1796 IntGdiDeleteDC( hdcMem
, FALSE
);
1800 IntGetDialogBaseUnits(VOID
)
1809 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1811 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1812 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1813 UserReleaseDC( 0, hdc
, FALSE
);
1820 /***********************************************************************
1823 * Calculate the size of the menu item and store it in lpitem->rect.
1825 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1826 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1829 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1830 UINT arrow_bitmap_width
;
1834 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1836 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1838 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1840 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1842 if (lpitem
->fType
& MF_OWNERDRAW
)
1844 MEASUREITEMSTRUCT mis
;
1845 mis
.CtlType
= ODT_MENU
;
1847 mis
.itemID
= lpitem
->wID
;
1848 mis
.itemData
= lpitem
->dwItemData
;
1849 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1851 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1852 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1853 * width of a menufont character to the width of an owner-drawn menu.
1855 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1857 /* under at least win95 you seem to be given a standard
1858 height for the menu and the height value is ignored */
1859 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1861 Rect
.bottom
+= mis
.itemHeight
;
1863 //lpitem->cxBmp = mis.itemWidth;
1864 //lpitem->cyBmp = mis.itemHeight;
1865 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1866 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1867 lpitem
->wID
, Rect
.right
-Rect
.left
,
1868 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1870 lpitem
->xItem
= Rect
.left
;
1871 lpitem
->yItem
= Rect
.top
;
1872 lpitem
->cxItem
= Rect
.right
;
1873 lpitem
->cyItem
= Rect
.bottom
;
1878 lpitem
->xItem
= orgX
;
1879 lpitem
->yItem
= orgY
;
1880 lpitem
->cxItem
= orgX
;
1881 lpitem
->cyItem
= orgY
;
1883 if (lpitem
->fType
& MF_SEPARATOR
)
1885 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1887 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1898 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1899 /* Keep the size of the bitmap in callback mode to be able
1900 * to draw it correctly */
1901 lpitem
->cxBmp
= size
.cx
;
1902 lpitem
->cyBmp
= size
.cy
;
1903 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1904 lpitem
->cxItem
+= size
.cx
+ 2;
1905 itemheight
= size
.cy
+ 2;
1907 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1908 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1909 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1910 lpitem
->dxTab
= lpitem
->cxItem
;
1911 lpitem
->cxItem
+= arrow_bitmap_width
;
1912 } else /* hbmpItem & MenuBar */ {
1913 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1914 lpitem
->cxItem
+= size
.cx
;
1915 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1916 itemheight
= size
.cy
;
1918 /* Special case: Minimize button doesn't have a space behind it. */
1919 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1920 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1921 lpitem
->cxItem
-= 1;
1924 else if (!menuBar
) {
1925 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1926 lpitem
->cxItem
+= check_bitmap_width
;
1927 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1928 lpitem
->dxTab
= lpitem
->cxItem
;
1929 lpitem
->cxItem
+= arrow_bitmap_width
;
1932 /* it must be a text item - unless it's the system menu */
1933 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1934 HFONT hfontOld
= NULL
;
1935 RECT rc
;// = lpitem->Rect;
1936 LONG txtheight
, txtwidth
;
1938 rc
.left
= lpitem
->xItem
;
1939 rc
.top
= lpitem
->yItem
;
1940 rc
.right
= lpitem
->cxItem
; // Do this for now......
1941 rc
.bottom
= lpitem
->cyItem
;
1943 if ( lpitem
->fState
& MFS_DEFAULT
) {
1944 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1947 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1949 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1950 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1952 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1954 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1957 int n
= (int)( p
- lpitem
->Xlpstr
);
1958 /* Item contains a tab (only meaningful in popup menus) */
1959 /* get text size before the tab */
1960 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1961 DT_SINGLELINE
|DT_CALCRECT
);
1962 txtwidth
= rc
.right
- rc
.left
;
1963 p
+= 1; /* advance past the Tab */
1964 /* get text size after the tab */
1965 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1966 DT_SINGLELINE
|DT_CALCRECT
);
1967 lpitem
->dxTab
+= txtwidth
;
1968 txtheight
= max( txtheight
, tmpheight
);
1969 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1970 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1972 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1973 DT_SINGLELINE
|DT_CALCRECT
);
1974 txtwidth
= rc
.right
- rc
.left
;
1975 lpitem
->dxTab
+= txtwidth
;
1977 lpitem
->cxItem
+= 2 + txtwidth
;
1978 itemheight
= max( itemheight
,
1979 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1983 NtGdiSelectFont (hdc
, hfontOld
);
1985 } else if( menuBar
) {
1986 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1988 lpitem
->cyItem
+= itemheight
;
1989 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1992 /***********************************************************************
1993 * MENU_GetMaxPopupHeight
1996 MENU_GetMaxPopupHeight(PMENU lppop
)
2000 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
2001 return lppop
->cyMax
;
2003 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
2004 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
2007 /***********************************************************************
2008 * MenuPopupMenuCalcSize
2010 * Calculate the size of a popup menu.
2012 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
2017 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
2018 BOOL textandbmp
= FALSE
;
2020 Menu
->cxMenu
= Menu
->cyMenu
= 0;
2021 if (Menu
->cItems
== 0) return;
2023 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2025 NtGdiSelectFont( hdc
, ghMenuFont
);
2030 Menu
->cxTextAlign
= 0;
2032 while (start
< Menu
->cItems
)
2034 lpitem
= &Menu
->rgItems
[start
];
2036 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2037 orgX
+= MENU_COL_SPACE
;
2040 maxTab
= maxTabWidth
= 0;
2041 /* Parse items until column break or end of menu */
2042 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2045 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2047 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2048 maxX
= max(maxX
, lpitem
->cxItem
);
2049 orgY
= lpitem
->cyItem
;
2050 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2052 maxTab
= max( maxTab
, lpitem
->dxTab
);
2053 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2055 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2058 /* Finish the column (set all items to the largest width found) */
2059 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2060 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2062 lpitem
->cxItem
= maxX
;
2063 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2064 lpitem
->dxTab
= maxTab
;
2066 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2069 Menu
->cxMenu
= maxX
;
2070 /* if none of the items have both text and bitmap then
2071 * the text and bitmaps are all aligned on the left. If there is at
2072 * least one item with both text and bitmap then bitmaps are
2073 * on the left and texts left aligned with the right hand side
2075 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2077 /* Adjust popup height if it exceeds maximum */
2078 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2079 Menu
->iMaxTop
= Menu
->cyMenu
;
2080 if (Menu
->cyMenu
>= maxHeight
)
2082 Menu
->cyMenu
= maxHeight
;
2083 Menu
->dwArrowsOn
= 1;
2087 Menu
->dwArrowsOn
= 0;
2089 UserReleaseDC( 0, hdc
, FALSE
);
2092 /***********************************************************************
2093 * MENU_MenuBarCalcSize
2095 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2096 * height is off by 1 pixel which causes lengthy window relocations when
2097 * active document window is maximized/restored.
2099 * Calculate the size of the menu bar.
2101 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2104 UINT start
, i
, helpPos
;
2105 int orgX
, orgY
, maxY
;
2107 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2108 if (lppop
->cItems
== 0) return;
2109 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2110 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2115 lppop
->cxTextAlign
= 0;
2116 while (start
< lppop
->cItems
)
2118 lpitem
= &lppop
->rgItems
[start
];
2119 orgX
= lprect
->left
;
2122 /* Parse items until line break or end of menu */
2123 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2125 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2127 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2129 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2130 //debug_print_menuitem (" item: ", lpitem, "");
2131 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2132 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2134 if (lpitem
->cxItem
> lprect
->right
)
2136 if (i
!= start
) break;
2137 else lpitem
->cxItem
= lprect
->right
;
2139 maxY
= max( maxY
, lpitem
->cyItem
);
2140 orgX
= lpitem
->cxItem
;
2143 /* Finish the line (set all items to the largest height found) */
2145 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2146 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2148 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2150 start
= i
; /* This works! */
2153 lprect
->bottom
= maxY
+ 1;
2154 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2156 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2157 /* the last item (if several lines, only move the last line) */
2158 if (helpPos
== ~0U) return;
2159 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2160 orgY
= lpitem
->yItem
;
2161 orgX
= lprect
->right
;
2162 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2163 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2164 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2165 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2166 lpitem
->cxItem
= orgX
;
2167 orgX
= lpitem
->xItem
;
2171 /***********************************************************************
2172 * MENU_DrawScrollArrows
2174 * Draw scroll arrows.
2176 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2178 UINT arrow_bitmap_height
;
2182 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2186 rect
.right
= lppop
->cxMenu
;
2187 rect
.bottom
= arrow_bitmap_height
;
2188 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2189 DrawFrameControl(hdc
, &rect
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2191 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2192 rect
.bottom
= lppop
->cyMenu
;
2193 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2194 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2195 Flags
= DFCS_INACTIVE
;
2196 DrawFrameControl(hdc
, &rect
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2199 /***********************************************************************
2202 * Draw a single menu item.
2204 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2205 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2209 BOOL flat_menu
= FALSE
;
2211 UINT arrow_bitmap_width
= 0;
2215 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2218 if (lpitem
->fType
& MF_SYSMENU
)
2220 if (!(Wnd
->style
& WS_MINIMIZE
))
2222 NC_GetInsideRect(Wnd
, &rect
);
2223 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2228 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2229 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2233 if (lpitem
->fState
& MF_HILITE
)
2235 if(menuBar
&& !flat_menu
) {
2236 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2237 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2239 if (lpitem
->fState
& MF_GRAYED
)
2240 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2242 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2243 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2248 if (lpitem
->fState
& MF_GRAYED
)
2249 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2251 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2252 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2255 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2256 //rect = lpitem->Rect;
2257 rect
.left
= lpitem
->xItem
;
2258 rect
.top
= lpitem
->yItem
;
2259 rect
.right
= lpitem
->cxItem
; // Do this for now......
2260 rect
.bottom
= lpitem
->cyItem
;
2262 MENU_AdjustMenuItemRect(Menu
, &rect
);
2264 if (lpitem
->fType
& MF_OWNERDRAW
)
2267 ** Experimentation under Windows reveals that an owner-drawn
2268 ** menu is given the rectangle which includes the space it requested
2269 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2270 ** and a popup-menu arrow. This is the value of lpitem->rect.
2271 ** Windows will leave all drawing to the application except for
2272 ** the popup-menu arrow. Windows always draws that itself, after
2273 ** the menu owner has finished drawing.
2276 COLORREF old_bk
, old_text
;
2278 dis
.CtlType
= ODT_MENU
;
2280 dis
.itemID
= lpitem
->wID
;
2281 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2283 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2284 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2285 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2286 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2287 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2288 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2289 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2290 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2291 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2294 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2295 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2296 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2297 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2299 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2300 old_bk
= GreGetBkColor(hdc
);
2301 old_text
= GreGetTextColor(hdc
);
2302 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2303 IntGdiSetBkColor(hdc
, old_bk
);
2304 IntGdiSetTextColor(hdc
, old_text
);
2305 /* Draw the popup-menu arrow */
2306 if (!menuBar
&& lpitem
->spSubMenu
)
2309 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2310 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2311 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2316 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2318 if (lpitem
->fState
& MF_HILITE
)
2322 RECTL_vInflateRect (&rect
, -1, -1);
2323 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2324 RECTL_vInflateRect (&rect
, 1, 1);
2325 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2331 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2332 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2336 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2341 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2343 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2345 /* vertical separator */
2346 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2351 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2353 rc
.bottom
= Height
- 3;
2356 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2357 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2358 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2359 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2360 NtGdiSelectPen( hdc
, oldPen
);
2363 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2366 /* horizontal separator */
2367 if (lpitem
->fType
& MF_SEPARATOR
)
2374 rc
.top
= (rc
.top
+ rc
.bottom
) / 2 - 1;
2377 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2378 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2379 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2380 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2381 NtGdiSelectPen( hdc
, oldPen
);
2384 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2388 /* helper lines for debugging */
2389 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2390 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2391 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2392 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2393 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2394 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2396 #if 0 // breaks mdi menu bar icons.
2398 /* calculate the bitmap rectangle in coordinates relative
2399 * to the item rectangle */
2401 if( lpitem
->hbmp
== HBMMENU_CALLBACK
)
2404 bmprc
.left
= lpitem
->Xlpstr
? MenuCharSize
.cx
: 0;
2406 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)
2408 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)
2411 bmprc
.left
= 4 + UserGetSystemMetrics(SM_CXMENUCHECK
);
2413 bmprc
.right
= bmprc
.left
+ lpitem
->cxBmp
;
2415 if( menuBar
&& !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2418 bmprc
.top
= (rect
.bottom
- rect
.top
- lpitem
->cyBmp
) / 2;
2420 bmprc
.bottom
= bmprc
.top
+ lpitem
->cyBmp
;
2426 INT y
= rect
.top
+ rect
.bottom
;
2428 BOOL checked
= FALSE
;
2429 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2430 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2431 /* Draw the check mark
2434 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2436 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2437 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2438 lpitem
->hbmpUnchecked
;
2439 if (bm
) /* we have a custom bitmap */
2441 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2443 NtGdiSelectBitmap( hdcMem
, bm
);
2444 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2445 check_bitmap_width
, check_bitmap_height
,
2446 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2447 IntGdiDeleteDC( hdcMem
, FALSE
);
2450 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2454 r
.right
= r
.left
+ check_bitmap_width
;
2455 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2456 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2457 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2461 if ( lpitem
->hbmp
)//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2463 RECT bmpRect
= rect
;
2464 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2465 bmpRect
.left
+= check_bitmap_width
+ 2;
2466 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2468 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2469 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2472 /* Draw the popup-menu arrow */
2473 if (lpitem
->spSubMenu
)
2476 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2477 rectTemp
.left
= rectTemp
.right
- check_bitmap_width
;
2478 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2481 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2482 rect
.left
+= check_bitmap_width
;
2483 rect
.right
-= arrow_bitmap_width
;
2485 else if( lpitem
->hbmp
)
2486 { /* Draw the bitmap */
2487 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
/*bmprc*/, Menu
, WndOwner
, odaction
, menuBar
);
2490 /* process text if present */
2496 UINT uFormat
= menuBar
?
2497 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2498 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2500 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2501 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2503 rect
.left
+= Menu
->cxTextAlign
;
2505 if ( lpitem
->fState
& MFS_DEFAULT
)
2507 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2512 rect
.left
+= lpitem
->cxBmp
;
2513 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2514 rect
.left
+= MenuCharSize
.cx
;
2515 rect
.right
-= MenuCharSize
.cx
;
2518 Text
= lpitem
->Xlpstr
;
2521 for (i
= 0; Text
[i
]; i
++)
2522 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2528 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
2530 RECTL_vOffsetRect(&rect
, +1, +1);
2536 if(lpitem
->fState
& MF_GRAYED
)
2538 if (!(lpitem
->fState
& MF_HILITE
) )
2540 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2541 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2542 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2543 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2545 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2547 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2549 /* paint the shortcut text */
2550 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2552 if (L
'\t' == Text
[i
])
2554 rect
.left
= lpitem
->dxTab
;
2555 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2559 rect
.right
= lpitem
->dxTab
;
2560 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2563 if (lpitem
->fState
& MF_GRAYED
)
2565 if (!(lpitem
->fState
& MF_HILITE
) )
2567 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2568 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2569 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2570 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2572 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2574 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2582 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
2584 RECTL_vOffsetRect(&rect
, -1, -1);
2589 NtGdiSelectFont (hdc
, hfontOld
);
2594 /***********************************************************************
2597 * Paint a popup menu.
2599 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2601 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2604 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2606 IntGetClientRect( wnd
, &rect
);
2608 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2609 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2610 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2614 /* FIXME: Maybe we don't have to fill the background manually */
2615 FillRect(hdc
, &rect
, brush
);
2617 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2620 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2621 /* draw menu items */
2622 if (menu
&& menu
->cItems
)
2627 item
= menu
->rgItems
;
2628 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2630 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2631 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2633 /* draw scroll arrows */
2634 if (menu
->dwArrowsOn
)
2636 MENU_DrawScrollArrows(menu
, hdc
);
2642 NtGdiSelectBrush( hdc
, hPrevBrush
);
2647 /**********************************************************************
2650 PWND
MENU_IsMenuActive(VOID
)
2652 return ValidateHwndNoErr(top_popup
);
2655 /**********************************************************************
2658 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2660 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2662 void MENU_EndMenu( PWND pwnd
)
2665 menu
= UserGetMenuObject(top_popup_hmenu
);
2666 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2668 if (fInsideMenuLoop
&& top_popup
)
2670 fInsideMenuLoop
= FALSE
;
2674 ERR("Already in End loop\n");
2679 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2685 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2688 HFONT FontOld
= NULL
;
2689 BOOL flat_menu
= FALSE
;
2691 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2695 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2703 if (Rect
== NULL
|| !pMenu
)
2705 return UserGetSystemMetrics(SM_CYMENU
);
2708 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2710 FontOld
= NtGdiSelectFont(hDC
, Font
);
2712 if (pMenu
->cyMenu
== 0)
2714 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2717 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2719 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2721 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2722 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2723 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2724 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2726 if (pMenu
->cItems
== 0)
2728 NtGdiSelectFont(hDC
, FontOld
);
2729 return UserGetSystemMetrics(SM_CYMENU
);
2732 for (i
= 0; i
< pMenu
->cItems
; i
++)
2734 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2737 NtGdiSelectFont(hDC
, FontOld
);
2739 return pMenu
->cyMenu
;
2742 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2745 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2749 // No menu. Do not reserve any space
2755 return UserGetSystemMetrics(SM_CYMENU
);
2760 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2762 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2764 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2766 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2768 return lppop
->cyMenu
;
2772 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2776 /***********************************************************************
2779 * Popup menu initialization before WM_ENTERMENULOOP.
2781 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2784 PPOPUPMENU pPopupMenu
;
2786 LARGE_STRING WindowName
;
2787 UNICODE_STRING ClassName
;
2788 DWORD ex_style
= WS_EX_PALETTEWINDOW
| WS_EX_DLGMODALFRAME
;
2790 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2792 menu
->spwndNotify
= pWndOwner
;
2794 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2795 ex_style
|= WS_EX_LAYOUTRTL
;
2797 ClassName
.Buffer
= WC_MENU
;
2798 ClassName
.Length
= 0;
2800 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2801 RtlZeroMemory(&Cs
, sizeof(Cs
));
2802 Cs
.style
= WS_POPUP
| WS_CLIPSIBLINGS
| WS_BORDER
;
2803 Cs
.dwExStyle
= ex_style
;
2804 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2805 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2806 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2807 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2808 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2810 /* NOTE: In Windows, top menu popup is not owned. */
2811 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
, WINVER
);
2813 if( !pWndCreated
) return FALSE
;
2816 // Setup pop up menu structure.
2818 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2820 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2822 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2823 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2824 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2826 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2827 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2828 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2829 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2830 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2832 if (pPopupMenu
->fRightButton
)
2833 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2835 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2837 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2838 menu
->fFlags
& MNF_RTOL
)
2840 pPopupMenu
->fDroppedLeft
= TRUE
;
2846 #define SHOW_DEBUGRECT 0
2849 static void DebugRect(const RECT
* rectl
, COLORREF color
)
2858 hdc
= UserGetDCEx(NULL
, 0, DCX_USESTYLE
);
2860 brush
= IntGdiCreateSolidBrush(color
);
2863 RECTL_vInflateRect(&rr
, 1, 1);
2864 FrameRect(hdc
, rectl
, brush
);
2865 FrameRect(hdc
, &rr
, brush
);
2867 NtGdiDeleteObjectApp(brush
);
2868 UserReleaseDC(NULL
, hdc
, TRUE
);
2871 static void DebugPoint(INT x
, INT y
, COLORREF color
)
2873 RECT r1
= {x
-10, y
, x
+10, y
};
2874 RECT r2
= {x
, y
-10, x
, y
+10};
2875 DebugRect(&r1
, color
);
2876 DebugRect(&r2
, color
);
2880 static BOOL
RECTL_Intersect(const RECT
* pRect
, INT x
, INT y
, UINT width
, UINT height
)
2882 RECT other
= {x
, y
, x
+ width
, y
+ height
};
2885 return RECTL_bIntersectRect(&dum
, pRect
, &other
);
2888 static BOOL
MENU_MoveRect(UINT flags
, INT
* x
, INT
* y
, INT width
, INT height
, const RECT
* pExclude
, PMONITOR monitor
)
2890 /* Figure out if we should move vertical or horizontal */
2891 if (flags
& TPM_VERTICAL
)
2893 /* Move in the vertical direction: TPM_BOTTOMALIGN means drop it above, otherways drop it below */
2894 if (flags
& TPM_BOTTOMALIGN
)
2896 if (pExclude
->top
- height
>= monitor
->rcMonitor
.top
)
2898 *y
= pExclude
->top
- height
;
2904 if (pExclude
->bottom
+ height
< monitor
->rcMonitor
.bottom
)
2906 *y
= pExclude
->bottom
;
2913 /* Move in the horizontal direction: TPM_RIGHTALIGN means drop it to the left, otherways go right */
2914 if (flags
& TPM_RIGHTALIGN
)
2916 if (pExclude
->left
- width
>= monitor
->rcMonitor
.left
)
2918 *x
= pExclude
->left
- width
;
2924 if (pExclude
->right
+ width
< monitor
->rcMonitor
.right
)
2926 *x
= pExclude
->right
;
2934 /***********************************************************************
2937 * Display a popup menu.
2939 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2940 INT x
, INT y
, const RECT
* pExclude
)
2946 USER_REFERENCE_ENTRY Ref
;
2947 BOOL bIsPopup
= (flags
& TPM_POPUPMENU
) != 0;
2949 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x\n",
2950 pwndOwner
, menu
, id
, x
, y
);
2952 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2954 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2955 menu
->iItem
= NO_SELECTED_ITEM
;
2960 DebugRect(pExclude
, RGB(255, 0, 0));
2963 menu
->dwArrowsOn
= 0;
2964 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2966 /* adjust popup menu pos so that it fits within the desktop */
2968 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXDLGFRAME
) * 2;
2969 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYDLGFRAME
) * 2;
2971 if (flags
& TPM_LAYOUTRTL
)
2972 flags
^= TPM_RIGHTALIGN
;
2974 if (flags
& TPM_RIGHTALIGN
)
2976 if (flags
& TPM_CENTERALIGN
)
2979 if (flags
& TPM_BOTTOMALIGN
)
2981 if (flags
& TPM_VCENTERALIGN
)
2984 /* FIXME: should use item rect */
2988 DebugPoint(x
, y
, RGB(0, 0, 255));
2990 monitor
= UserMonitorFromPoint( ptx
, MONITOR_DEFAULTTONEAREST
);
2992 /* We are off the right side of the screen */
2993 if (x
+ width
> monitor
->rcMonitor
.right
)
2995 if ((x
- width
) < monitor
->rcMonitor
.left
|| x
>= monitor
->rcMonitor
.right
)
2996 x
= monitor
->rcMonitor
.right
- width
;
3001 /* We are off the left side of the screen */
3002 if (x
< monitor
->rcMonitor
.left
)
3004 /* Re-orient the menu around the x-axis */
3007 if (x
< monitor
->rcMonitor
.left
|| x
>= monitor
->rcMonitor
.right
|| bIsPopup
)
3008 x
= monitor
->rcMonitor
.left
;
3011 /* Same here, but then the top */
3012 if (y
< monitor
->rcMonitor
.top
)
3016 if (y
< monitor
->rcMonitor
.top
|| y
>= monitor
->rcMonitor
.bottom
|| bIsPopup
)
3017 y
= monitor
->rcMonitor
.top
;
3020 /* And the bottom */
3021 if (y
+ height
> monitor
->rcMonitor
.bottom
)
3023 if ((y
- height
) < monitor
->rcMonitor
.top
|| y
>= monitor
->rcMonitor
.bottom
)
3024 y
= monitor
->rcMonitor
.bottom
- height
;
3033 if (RECTL_bIntersectRect(&Cleaned
, pExclude
, &monitor
->rcMonitor
) &&
3034 RECTL_Intersect(&Cleaned
, x
, y
, width
, height
))
3036 UINT flag_mods
[] = {
3037 0, /* First try the 'normal' way */
3038 TPM_BOTTOMALIGN
| TPM_RIGHTALIGN
, /* Then try the opposite side */
3039 TPM_VERTICAL
, /* Then swap horizontal / vertical */
3040 TPM_BOTTOMALIGN
| TPM_RIGHTALIGN
| TPM_VERTICAL
, /* Then the other side again (still swapped hor/ver) */
3044 for (n
= 0; n
< RTL_NUMBER_OF(flag_mods
); ++n
)
3049 /* Try to move a bit around */
3050 if (MENU_MoveRect(flags
^ flag_mods
[n
], &tx
, &ty
, width
, height
, &Cleaned
, monitor
) &&
3051 !RECTL_Intersect(&Cleaned
, tx
, ty
, width
, height
))
3058 /* If none worked, we go with the original x/y */
3064 RECT rr
= {x
, y
, x
+ width
, y
+ height
};
3065 DebugRect(&rr
, RGB(0, 255, 0));
3069 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
3073 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
3078 top_popup
= menu
->hWnd
;
3079 top_popup_hmenu
= UserHMGetHandle(menu
);
3082 /* Display the window */
3083 UserRefObjectCo(pWnd
, &Ref
);
3084 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
3086 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
3088 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3089 UserDerefObjectCo(pWnd
);
3094 /***********************************************************************
3095 * MENU_EnsureMenuItemVisible
3097 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
3099 USER_REFERENCE_ENTRY Ref
;
3100 if (lppop
->dwArrowsOn
)
3102 ITEM
*item
= &lppop
->rgItems
[wIndex
];
3103 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
3104 UINT nOldPos
= lppop
->iTop
;
3106 UINT arrow_bitmap_height
;
3107 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
3109 IntGetClientRect(pWnd
, &rc
);
3111 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
3113 rc
.top
+= arrow_bitmap_height
;
3114 rc
.bottom
-= arrow_bitmap_height
;
3116 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
3117 UserRefObjectCo(pWnd
, &Ref
);
3118 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
3120 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
3121 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
3122 MENU_DrawScrollArrows(lppop
, hdc
);
3123 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3125 else if (item
->yItem
< lppop
->iTop
)
3127 lppop
->iTop
= item
->yItem
;
3128 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
3129 MENU_DrawScrollArrows(lppop
, hdc
);
3130 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3132 UserDerefObjectCo(pWnd
);
3136 /***********************************************************************
3139 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
3140 BOOL sendMenuSelect
, PMENU topmenu
)
3145 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
3147 if (!menu
|| !menu
->cItems
) return;
3149 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3153 if (menu
->iItem
== wIndex
) return;
3155 if (menu
->fFlags
& MNF_POPUP
)
3156 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
3158 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3161 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
3162 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
3163 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
3166 NtGdiSelectFont( hdc
, ghMenuFont
);
3168 /* Clear previous highlighted item */
3169 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3171 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
3172 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
3173 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
3177 /* Highlight new item (if any) */
3178 menu
->iItem
= wIndex
;
3179 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3181 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
3183 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
3184 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
3185 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
3186 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3190 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3191 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3192 ip
->fType
| ip
->fState
|
3193 (ip
->spSubMenu
? MF_POPUP
: 0) |
3194 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3196 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3199 else if (sendMenuSelect
)
3204 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3205 if (pos
!= NO_SELECTED_ITEM
)
3207 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3208 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3209 (ip
->spSubMenu
? MF_POPUP
: 0) |
3210 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3212 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3216 UserReleaseDC(pWnd
, hdc
, FALSE
);
3219 /***********************************************************************
3222 * Moves currently selected item according to the Offset parameter.
3223 * If there is no selection then it should select the last item if
3224 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3226 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3230 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3232 if ((!menu
) || (!menu
->rgItems
)) return;
3234 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3236 if ( menu
->cItems
== 1 )
3239 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3241 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3243 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3248 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3249 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3250 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3252 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3257 /***********************************************************************
3260 * Hide the sub-popup menus of this menu.
3262 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3263 BOOL SendMenuSelect
, UINT wFlags
)
3265 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3267 if ( Menu
&& top_popup
)
3271 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3273 Item
= &Menu
->rgItems
[Menu
->iItem
];
3274 if (!(Item
->spSubMenu
) ||
3275 !(Item
->fState
& MF_MOUSESELECT
)) return;
3276 Item
->fState
&= ~MF_MOUSESELECT
;
3281 if (Item
->spSubMenu
)
3284 if (!VerifyMenu(Item
->spSubMenu
)) return;
3285 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3286 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3287 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3288 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3289 co_UserDestroyWindow(pWnd
);
3291 /* Native returns handle to destroyed window */
3292 if (!(wFlags
& TPM_NONOTIFY
))
3294 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3295 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3298 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3299 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3301 Item
->spSubMenu
->hWnd
= NULL
;
3307 /***********************************************************************
3310 * Display the sub-menu of the selected item of this menu.
3311 * Return the handle of the submenu, or menu if no submenu to display.
3313 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3315 RECT Rect
, ParentRect
;
3320 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3322 if (!Menu
) return Menu
;
3324 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3326 Item
= &Menu
->rgItems
[Menu
->iItem
];
3327 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3330 /* message must be sent before using item,
3331 because nearly everything may be changed by the application ! */
3333 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3334 if (!(Flags
& TPM_NONOTIFY
))
3336 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3337 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3338 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3341 Item
= &Menu
->rgItems
[Menu
->iItem
];
3342 //Rect = ItemInfo.Rect;
3343 Rect
.left
= Item
->xItem
;
3344 Rect
.top
= Item
->yItem
;
3345 Rect
.right
= Item
->cxItem
; // Do this for now......
3346 Rect
.bottom
= Item
->cyItem
;
3348 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3350 /* Grab the rect of our (entire) parent menu, so we can try to not overlap it */
3351 if (Menu
->fFlags
& MNF_POPUP
)
3353 if (!IntGetWindowRect(pWnd
, &ParentRect
))
3359 /* Ensure we can slightly overlap our parent */
3360 RECTL_vInflateRect(&ParentRect
, -UserGetSystemMetrics(SM_CXEDGE
) * 2, 0);
3364 /* Inside the menu bar, we do not want to grab the entire window... */
3367 RECTL_vOffsetRect(&ParentRect
, pWnd
->rcWindow
.left
, pWnd
->rcWindow
.top
);
3370 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3371 if (!(Item
->fState
& MF_HILITE
))
3373 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3374 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3376 NtGdiSelectFont(Dc
, ghMenuFont
);
3378 Item
->fState
|= MF_HILITE
;
3379 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3380 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3382 UserReleaseDC(pWnd
, Dc
, FALSE
);
3385 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3387 Item
->xItem
= Rect
.left
;
3388 Item
->yItem
= Rect
.top
;
3389 Item
->cxItem
= Rect
.right
; // Do this for now......
3390 Item
->cyItem
= Rect
.bottom
;
3392 Item
->fState
|= MF_MOUSESELECT
;
3394 if (IS_SYSTEM_MENU(Menu
))
3396 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3398 NC_GetSysPopupPos(pWnd
, &Rect
);
3399 /* Ensure we do not overlap this */
3401 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3402 Rect
.top
= Rect
.bottom
;
3403 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3404 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3408 IntGetWindowRect(pWnd
, &Rect
);
3409 if (Menu
->fFlags
& MNF_POPUP
)
3412 rc
.left
= Item
->xItem
;
3413 rc
.top
= Item
->yItem
;
3414 rc
.right
= Item
->cxItem
;
3415 rc
.bottom
= Item
->cyItem
;
3417 MENU_AdjustMenuItemRect(Menu
, &rc
);
3419 /* The first item in the popup menu has to be at the
3420 same y position as the focused menu item */
3421 if(Flags
& TPM_LAYOUTRTL
)
3422 Rect
.left
+= UserGetSystemMetrics(SM_CXDLGFRAME
);
3424 Rect
.left
+= rc
.right
- UserGetSystemMetrics(SM_CXDLGFRAME
);
3430 if(Flags
& TPM_LAYOUTRTL
)
3431 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3433 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3434 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3435 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3436 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3440 /* Next menu does not need to be shown vertical anymore */
3441 if (Menu
->fFlags
& MNF_POPUP
)
3442 Flags
&= (~TPM_VERTICAL
);
3446 /* use default alignment for submenus */
3447 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3449 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3451 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3452 Rect
.left
, Rect
.top
, &ParentRect
);
3455 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3457 return Item
->spSubMenu
;
3460 /***********************************************************************
3461 * MenuExecFocusedItem
3463 * Execute a menu item (for instance when user pressed Enter).
3464 * Return the wID of the executed item. Otherwise, -1 indicating
3465 * that no menu item was executed, -2 if a popup is shown;
3466 * Have to receive the flags for the TrackPopupMenu options to avoid
3467 * sending unwanted message.
3470 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3474 TRACE("%p menu=%p\n", pmt
, Menu
);
3476 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3481 Item
= &Menu
->rgItems
[Menu
->iItem
];
3483 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3485 if (!(Item
->spSubMenu
))
3487 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3489 /* If TPM_RETURNCMD is set you return the id, but
3490 do not send a message to the owner */
3491 if (!(Flags
& TPM_RETURNCMD
))
3493 if (Menu
->fFlags
& MNF_SYSMENU
)
3495 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3496 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3500 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3502 if (dwStyle
& MNS_NOTIFYBYPOS
)
3503 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3505 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3513 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3520 /***********************************************************************
3521 * MenuSwitchTracking
3523 * Helper function for menu navigation routines.
3525 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3527 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3529 if ( pmt
->TopMenu
!= PtMenu
&&
3530 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3532 /* both are top level menus (system and menu-bar) */
3533 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3534 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3535 pmt
->TopMenu
= PtMenu
;
3539 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3542 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3545 /***********************************************************************
3548 * Return TRUE if we can go on with menu tracking.
3550 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3552 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3558 if (IS_SYSTEM_MENU(PtMenu
))
3560 item
= PtMenu
->rgItems
;
3564 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3569 if (PtMenu
->iItem
!= id
)
3570 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3572 /* If the popup menu is not already "popped" */
3573 if (!(item
->fState
& MF_MOUSESELECT
))
3575 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3580 /* Else the click was on the menu bar, finish the tracking */
3585 /***********************************************************************
3588 * Return the value of MenuExecFocusedItem if
3589 * the selected item was not a popup. Else open the popup.
3590 * A -1 return value indicates that we go on with menu tracking.
3593 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3595 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3602 if ( IS_SYSTEM_MENU(PtMenu
) )
3604 item
= PtMenu
->rgItems
;
3608 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3611 if (item
&& ( PtMenu
->iItem
== Id
))
3613 if (!(item
->spSubMenu
))
3615 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3616 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3617 return ExecutedMenuId
;
3620 /* If we are dealing with the menu bar */
3621 /* and this is a click on an already "popped" item: */
3622 /* Stop the menu tracking and close the opened submenus */
3623 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3628 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3630 PtMenu
->TimeToHide
= TRUE
;
3636 /***********************************************************************
3639 * Walks menu chain trying to find a menu pt maps to.
3641 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3646 if (!menu
) return NULL
;
3648 /* try subpopup first (if any) */
3649 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3651 pItem
= menu
->rgItems
;
3652 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3653 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3655 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3659 /* check the current window (avoiding WM_HITTEST) */
3662 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3663 INT ht
= GetNCHitEx(pWnd
, pt
);
3664 if ( menu
->fFlags
& MNF_POPUP
)
3666 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3668 else if (ht
== HTSYSMENU
)
3669 ret
= get_win_sys_menu(menu
->hWnd
);
3670 else if (ht
== HTMENU
)
3671 ret
= IntGetMenu( menu
->hWnd
);
3676 /***********************************************************************
3679 * Return TRUE if we can go on with menu tracking.
3681 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3683 UINT Index
= NO_SELECTED_ITEM
;
3687 if (IS_SYSTEM_MENU(PtMenu
))
3690 //// ReactOS only HACK: CORE-2338
3691 // Windows tracks mouse moves to the system menu but does not open it.
3692 // Only keyboard tracking can do that.
3694 TRACE("SystemMenu\n");
3695 return TRUE
; // Stay inside the Loop!
3698 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3701 if (Index
== NO_SELECTED_ITEM
)
3703 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3705 else if (PtMenu
->iItem
!= Index
)
3707 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3708 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3713 /***********************************************************************
3716 * Return the handle of the selected sub-popup menu (if any).
3718 static PMENU
MENU_GetSubPopup( PMENU menu
)
3722 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3724 item
= &menu
->rgItems
[menu
->iItem
];
3725 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3727 return item
->spSubMenu
;
3732 /***********************************************************************
3735 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3737 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3741 /* When skipping left, we need to do something special after the
3743 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3747 /* When skipping right, for the non-system menu, we need to
3748 handle the last non-special menu item (ie skip any window
3749 icons such as MDI maximize, restore or close) */
3750 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3752 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3753 while (i
< pmt
->TopMenu
->cItems
) {
3754 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3755 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3759 if (i
== pmt
->TopMenu
->cItems
) {
3763 /* When skipping right, we need to cater for the system menu */
3764 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3766 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3773 MDINEXTMENU NextMenu
;
3780 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3781 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3782 NextMenu
.hmenuNext
= NULL
;
3783 NextMenu
.hwndNext
= NULL
;
3784 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3786 TRACE("%p [%p] -> %p [%p]\n",
3787 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3789 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3791 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3792 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3794 /* switch to the menu bar */
3796 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3800 Id
= MenuTmp
->cItems
- 1;
3802 /* Skip backwards over any system predefined icons,
3803 eg. MDI close, restore etc icons */
3805 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3806 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3809 hNewMenu
= UserHMGetHandle(MenuTmp
);
3811 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3813 /* switch to the system menu */
3814 MenuTmp
= get_win_sys_menu(hNewWnd
);
3815 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3820 else /* application returned a new menu to switch to */
3822 hNewMenu
= NextMenu
.hmenuNext
;
3823 hNewWnd
= NextMenu
.hwndNext
;
3825 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3827 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3829 /* get the real system menu */
3830 MenuTmp
= get_win_sys_menu(hNewWnd
);
3831 hNewMenu
= UserHMGetHandle(MenuTmp
);
3833 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3835 /* FIXME: Not sure what to do here;
3836 * perhaps try to track NewMenu as a popup? */
3838 WARN(" -- got confused.\n");
3845 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3847 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3849 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3850 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3853 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3855 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3856 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3857 ///// Use thread pms!!!!
3858 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3859 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3860 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3861 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3864 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3865 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3872 /***********************************************************************
3875 * The idea is not to show the popup if the next input message is
3876 * going to hide it anyway.
3878 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3882 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3884 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3885 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3890 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3891 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3893 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3894 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3895 if( msg
.message
== WM_KEYDOWN
&&
3896 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3898 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3904 /* failures go through this */
3905 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3909 /***********************************************************************
3912 * Handle a VK_ESCAPE key event in a menu.
3914 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3916 BOOL EndMenu
= TRUE
;
3918 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3920 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3922 PMENU MenuPrev
, MenuTmp
;
3924 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3926 /* close topmost popup */
3927 while (MenuTmp
!= pmt
->CurrentMenu
)
3930 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3933 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3934 pmt
->CurrentMenu
= MenuPrev
;
3942 /***********************************************************************
3945 * Handle a VK_LEFT key event in a menu.
3947 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
, UINT msg
)
3949 PMENU MenuTmp
, MenuPrev
;
3952 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3954 /* Try to move 1 column left (if possible) */
3955 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3957 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3961 /* close topmost popup */
3962 while (MenuTmp
!= pmt
->CurrentMenu
)
3965 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3968 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3969 pmt
->CurrentMenu
= MenuPrev
;
3971 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3973 /* move menu bar selection if no more popups are left */
3975 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3976 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3978 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3980 /* A sublevel menu was displayed - display the next one
3981 * unless there is another displacement coming up */
3983 if (!MENU_SuspendPopup(pmt
, msg
))
3984 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3990 /***********************************************************************
3993 * Handle a VK_RIGHT key event in a menu.
3995 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
, UINT msg
)
4000 TRACE("MenuKeyRight called, cur %p, top %p.\n",
4001 pmt
->CurrentMenu
, pmt
->TopMenu
);
4003 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
4005 /* If already displaying a popup, try to display sub-popup */
4007 menutmp
= pmt
->CurrentMenu
;
4008 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
4010 /* if subpopup was displayed then we are done */
4011 if (menutmp
!= pmt
->CurrentMenu
) return;
4014 /* Check to see if there's another column */
4015 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
4017 TRACE("Going to %d.\n", NextCol
);
4018 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
4022 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
4024 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
4026 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
4027 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
4034 /* try to move to the next item */
4035 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
4036 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
4038 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
4040 if ( !MENU_SuspendPopup(pmt
, msg
) )
4041 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
4046 /***********************************************************************
4049 * Menu tracking code.
4051 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
4056 INT executedMenuId
= -1;
4060 BOOL enterIdleSent
= FALSE
;
4061 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4063 if (pti
!= pwnd
->head
.pti
)
4065 ERR("Not the same PTI!!!!\n");
4069 mt
.CurrentMenu
= pmenu
;
4075 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n",
4076 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
));
4078 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
4080 if (wFlags
& TPM_BUTTONDOWN
)
4082 /* Get the result in order to start the tracking or not */
4083 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
4084 fInsideMenuLoop
= fRemove
;
4087 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
4089 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
4091 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4092 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4093 co_UserSetCapture(NULL
); /* release the capture */
4097 capture_win
= IntGetCapture();
4099 while (fInsideMenuLoop
)
4101 BOOL ErrorExit
= FALSE
;
4102 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
4105 /* we have to keep the message in the queue until it's
4106 * clear that menu loop is not over yet. */
4110 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
4112 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
4113 /* remove the message from the queue */
4114 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4118 /* ReactOS Checks */
4119 if (!VerifyWnd(mt
.OwnerWnd
) ||
4120 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
4121 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
4122 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
4124 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
4130 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
4131 enterIdleSent
= TRUE
;
4132 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
4134 co_IntWaitMessage(NULL
, 0, 0);
4138 if (ErrorExit
) break; // Gracefully dropout.
4140 /* check if EndMenu() tried to cancel us, by posting this message */
4141 if (msg
.message
== WM_CANCELMODE
)
4143 /* we are now out of the loop */
4144 fInsideMenuLoop
= FALSE
;
4146 /* remove the message from the queue */
4147 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4149 /* break out of internal loop, ala ESCAPE */
4155 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
4156 enterIdleSent
=FALSE
;
4159 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
4162 * Use the mouse coordinates in lParam instead of those in the MSG
4163 * struct to properly handle synthetic messages. They are already
4164 * in screen coordinates.
4166 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
4167 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
4169 /* Find a menu for this mouse event */
4170 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
4174 /* no WM_NC... messages in captured state */
4176 case WM_RBUTTONDBLCLK
:
4177 case WM_RBUTTONDOWN
:
4178 if (!(wFlags
& TPM_RIGHTBUTTON
))
4180 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
4184 case WM_LBUTTONDBLCLK
:
4185 case WM_LBUTTONDOWN
:
4186 /* If the message belongs to the menu, removes it from the queue */
4187 /* Else, end menu tracking */
4188 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
4189 fInsideMenuLoop
= fRemove
;
4190 if ( msg
.message
== WM_LBUTTONDBLCLK
||
4191 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
4195 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
4198 /* Check if a menu was selected by the mouse */
4201 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
4203 /* End the loop if executedMenuId is an item ID */
4204 /* or if the job was done (executedMenuId = 0). */
4205 fRemove
= (executedMenuId
!= -1);
4206 fInsideMenuLoop
= !fRemove
;
4208 /* No menu was selected by the mouse */
4209 /* if the function was called by TrackPopupMenu, continue
4210 with the menu tracking. If not, stop it */
4212 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4217 /* the selected menu item must be changed every time */
4218 /* the mouse moves. */
4221 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4223 } /* switch(msg.message) - mouse */
4225 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4227 fRemove
= TRUE
; /* Keyboard messages are always removed */
4236 fInsideMenuLoop
= FALSE
;
4241 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4242 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4246 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4247 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4248 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4249 else /* otherwise try to move selection */
4250 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4254 MENU_KeyLeft( &mt
, wFlags
, msg
.message
);
4258 MENU_KeyRight( &mt
, wFlags
, msg
.message
);
4262 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4268 hi
.cbSize
= sizeof(HELPINFO
);
4269 hi
.iContextType
= HELPINFO_MENUITEM
;
4270 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4273 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4274 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4275 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4276 hi
.MousePos
= msg
.pt
;
4277 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4282 IntTranslateKbdMessage(&msg
, 0);
4285 break; /* WM_KEYDOWN */
4293 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4295 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4296 fEndMenu
= (executedMenuId
!= -2);
4297 fInsideMenuLoop
= !fEndMenu
;
4301 /* Hack to avoid control chars. */
4302 /* We will find a better way real soon... */
4303 if (msg
.wParam
< 32) break;
4305 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4307 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4308 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4311 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4312 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4313 fEndMenu
= (executedMenuId
!= -2);
4314 fInsideMenuLoop
= !fEndMenu
;
4318 } /* switch(msg.message) - kbd */
4322 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4323 IntDispatchMessage( &msg
);
4327 if (fInsideMenuLoop
) fRemove
= TRUE
;
4329 /* finally remove message from the queue */
4331 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4332 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4333 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4336 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4337 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4338 co_UserSetCapture(NULL
); /* release the capture */
4340 /* If dropdown is still painted and the close box is clicked on
4341 then the menu will be destroyed as part of the DispatchMessage above.
4342 This will then invalidate the menu handle in mt.hTopMenu. We should
4343 check for this first. */
4344 if ( VerifyMenu( mt
.TopMenu
) )
4346 if (VerifyWnd(mt
.OwnerWnd
))
4348 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4350 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4352 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4355 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4357 co_UserDestroyWindow(pwndTM
);
4359 mt
.TopMenu
->hWnd
= NULL
;
4361 if (!(wFlags
& TPM_NONOTIFY
))
4363 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4364 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4367 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4368 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4371 /* Reset the variable for hiding menu */
4372 mt
.TopMenu
->TimeToHide
= FALSE
;
4375 EngSetLastError( ERROR_SUCCESS
);
4376 /* The return value is only used by TrackPopupMenu */
4377 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4378 if (executedMenuId
== -1) executedMenuId
= 0;
4379 return executedMenuId
;
4382 /***********************************************************************
4385 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4388 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4390 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4392 co_UserHideCaret(0);
4394 /* This makes the menus of applications built with Delphi work.
4395 * It also enables menus to be displayed in more than one window,
4396 * but there are some bugs left that need to be fixed in this case.
4400 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4404 top_popup
= Menu
->hWnd
;
4405 top_popup_hmenu
= UserHMGetHandle(Menu
);
4408 fInsideMenuLoop
= TRUE
;
4411 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4412 if (!(wFlags
& TPM_NONOTIFY
))
4414 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4418 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4420 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4421 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4422 co_UserSetCapture(capture_win
); // 2
4423 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4425 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4427 if (!(wFlags
& TPM_NONOTIFY
))
4429 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4430 /* If an app changed/recreated menu bar entries in WM_INITMENU
4431 * menu sizes will be recalculated once the menu created/shown.
4435 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4437 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4442 /***********************************************************************
4445 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4447 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4449 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4451 if (!(wFlags
& TPM_NONOTIFY
))
4452 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4454 co_UserShowCaret(0);
4457 top_popup_hmenu
= NULL
;
4462 /***********************************************************************
4463 * MenuTrackMouseMenuBar
4465 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4467 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4469 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) ); // See 74276 and CORE-12801
4470 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
| TPM_VERTICAL
;
4472 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4474 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4475 if (VerifyMenu(pMenu
))
4477 /* map point to parent client coordinates */
4478 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4479 if (Parent
!= UserGetDesktopWindow())
4481 IntScreenToClient(Parent
, &pt
);
4484 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4485 /* fetch the window menu again, it may have changed */
4486 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4487 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
);
4488 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4492 /***********************************************************************
4493 * MenuTrackKbdMenuBar
4495 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4497 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4499 UINT uItem
= NO_SELECTED_ITEM
;
4501 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4503 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4505 /* find window that has a menu */
4507 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4508 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4510 /* check if we have to track a system menu */
4512 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4513 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4515 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4516 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4518 wParam
|= HTSYSMENU
; /* prevent item lookup */
4521 if (!VerifyMenu( TrackMenu
)) return;
4523 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4525 /* fetch the window menu again, it may have changed */
4526 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4528 if( wChar
&& wChar
!= ' ' )
4530 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4531 if ( uItem
>= (UINT
)(-2) )
4533 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4534 /* schedule end of menu tracking */
4535 wFlags
|= TF_ENDMENU
;
4540 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4542 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4544 if( uItem
== NO_SELECTED_ITEM
)
4545 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4547 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4551 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
);
4552 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4555 /**********************************************************************
4556 * TrackPopupMenuEx (USER32.@)
4558 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4559 PWND pWnd
, LPTPMPARAMS lpTpm
)
4562 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4564 if (pti
!= pWnd
->head
.pti
)
4566 ERR("Must be the same pti!\n");
4570 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4571 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4572 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4574 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4576 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4580 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4582 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4584 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4585 if (!(wFlags
& TPM_NONOTIFY
))
4587 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4590 if (menu
->fFlags
& MNF_SYSMENU
)
4591 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4593 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
| TPM_POPUPMENU
, x
, y
, lpTpm
? &lpTpm
->rcExclude
: NULL
))
4594 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
);
4597 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4598 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4599 co_UserSetCapture(NULL
); /* release the capture */
4602 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4606 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4607 if (pwndM
) // wine hack around this with their destroy function.
4609 if (!(pWnd
->state
& WNDS_DESTROYED
))
4610 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4614 if (!(wFlags
& TPM_NONOTIFY
))
4616 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4617 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4635 PPOPUPMENU pPopupMenu
;
4639 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4645 if (Message
!= WM_NCCREATE
)
4647 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4650 Wnd
->fnid
= FNID_MENU
;
4651 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4652 if (pPopupMenu
== NULL
)
4656 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4657 pPopupMenu
->spwndPopupMenu
= Wnd
;
4658 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4659 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4665 if (Wnd
->fnid
!= FNID_MENU
)
4667 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4670 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4678 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4679 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4680 if (pPopupMenu
->spmenu
)
4682 UserReferenceObject(pPopupMenu
->spmenu
);
4687 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4688 *lResult
= MA_NOACTIVATE
;
4694 IntBeginPaint(Wnd
, &ps
);
4695 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4696 IntEndPaint(Wnd
, &ps
);
4700 case WM_PRINTCLIENT
:
4702 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4711 /* zero out global pointer in case resident popup window was destroyed. */
4714 if (UserHMGetHandle(Wnd
) == top_popup
)
4717 top_popup_hmenu
= NULL
;
4722 ERR("No Window Pop Up!\n");
4728 if (pPopupMenu
->spmenu
)
4730 IntReleaseMenuObject(pPopupMenu
->spmenu
);
4732 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4733 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4734 Wnd
->fnid
= FNID_DESTROY
;
4738 case MM_SETMENUHANDLE
: // wine'isms
4741 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4744 ERR("Bad Menu Handle\n");
4747 UserReferenceObject(pmenu
);
4748 if (pPopupMenu
->spmenu
)
4750 IntReleaseMenuObject(pPopupMenu
->spmenu
);
4752 pPopupMenu
->spmenu
= pmenu
;
4756 case MM_GETMENUHANDLE
: // wine'isms
4758 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4762 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4764 ERR("Someone is passing unknown menu messages %d\n",Message
);
4766 TRACE("PMWP to IDWP %d\n",Message
);
4767 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4775 IntHiliteMenuItem(PWND WindowObject
,
4781 UINT uItem
= uItemHilite
;
4783 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4785 if (uHilite
& MF_HILITE
)
4787 MenuItem
->fState
|= MF_HILITE
;
4791 MenuItem
->fState
&= ~MF_HILITE
;
4793 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4794 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4795 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4797 return TRUE
; // Always returns true!!!!
4801 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4805 DWORD dwExStyle
= 0;
4806 BOOLEAN retValue
= TRUE
;
4808 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4810 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4812 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4814 dwStyle
= pWindowObject
->style
;
4815 dwExStyle
= pWindowObject
->ExStyle
;
4817 bti
->rcTitleBar
.top
= 0;
4818 bti
->rcTitleBar
.left
= 0;
4819 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4820 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4822 /* Is it iconiced ? */
4823 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4825 /* Remove frame from rectangle */
4826 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4828 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4829 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4831 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4833 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4834 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4836 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4838 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4839 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4842 /* We have additional border information if the window
4843 * is a child (but not an MDI child) */
4844 if ( (dwStyle
& WS_CHILD
) &&
4845 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4847 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4849 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4850 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4853 if (dwExStyle
& WS_EX_STATICEDGE
)
4855 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4856 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4861 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4862 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4863 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4865 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4866 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4868 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4869 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4873 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4874 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4875 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4878 if (dwStyle
& WS_CAPTION
)
4880 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4881 if (dwStyle
& WS_SYSMENU
)
4883 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4885 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4886 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4890 if (!(dwStyle
& WS_MINIMIZEBOX
))
4892 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4894 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4896 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4900 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4902 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4904 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4906 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4911 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4912 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4913 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4914 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4919 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4924 EngSetLastError(ERROR_INVALID_PARAMETER
);
4936 LPCMENUITEMINFOW UnsafeItemInfo
,
4937 PUNICODE_STRING lpstr
)
4940 ROSMENUITEMINFO ItemInfo
;
4942 /* Try to copy the whole MENUITEMINFOW structure */
4943 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4944 if (NT_SUCCESS(Status
))
4946 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4947 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4949 EngSetLastError(ERROR_INVALID_PARAMETER
);
4952 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4955 /* Try to copy without last field (not present in older versions) */
4956 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4957 if (NT_SUCCESS(Status
))
4959 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4961 EngSetLastError(ERROR_INVALID_PARAMETER
);
4964 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4965 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4968 SetLastNtError(Status
);
4972 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4977 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4982 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4984 if (pItem
->spSubMenu
)
4986 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4989 return (pItem
->fType
| pItem
->fState
);
4992 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4997 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
5002 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
5004 if (pItem
->spSubMenu
)
5006 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
5012 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
5014 PMENU menu
, pSubTarget
;
5016 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
5017 return NO_SELECTED_ITEM
;
5019 pSubTarget
= UserGetMenuObject(hSubTarget
);
5021 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
5023 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
5029 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
5031 PWINSTATION_OBJECT WinStaObject
;
5035 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
5037 if (gpepCSRSS
!= CurrentProcess
)
5040 * gpepCSRSS does not have a Win32WindowStation
5043 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
5049 if (!NT_SUCCESS(Status
))
5051 ERR("Validation of window station handle (%p) failed\n",
5052 CurrentProcess
->Win32WindowStation
);
5053 SetLastNtError(Status
);
5056 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
5057 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
5059 ERR("Desktop Window Station does not match Process one!\n");
5061 ObDereferenceObject(WinStaObject
);
5065 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
5068 if (Menu
) UserDereferenceObject(Menu
);
5069 return (HMENU
)Handle
;
5077 PROSMENUITEMINFO ItemInfo
,
5079 PUNICODE_STRING lpstr
)
5084 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
5086 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
5091 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
5095 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
5105 PROSMENUITEMINFO UnsafeItemInfo
,
5107 PUNICODE_STRING lpstr
)
5110 ROSMENUITEMINFO ItemInfo
;
5115 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
5116 if (! NT_SUCCESS(Status
))
5118 SetLastNtError(Status
);
5121 if ( Size
!= sizeof(MENUITEMINFOW
) &&
5122 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
5123 Size
!= sizeof(ROSMENUITEMINFO
) )
5125 EngSetLastError(ERROR_INVALID_PARAMETER
);
5128 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
5129 if (! NT_SUCCESS(Status
))
5131 SetLastNtError(Status
);
5134 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
5136 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
5137 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
5139 EngSetLastError(ERROR_INVALID_PARAMETER
);
5143 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
5145 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
5146 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
5149 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
5155 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
5159 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
5162 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
5163 if (! NT_SUCCESS(Status
))
5165 SetLastNtError(Status
);
5177 PROSMENUINFO UnsafeMenuInfo
,
5183 ROSMENUINFO MenuInfo
;
5185 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
5186 if (! NT_SUCCESS(Status
))
5188 SetLastNtError(Status
);
5191 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
5193 EngSetLastError(ERROR_INVALID_PARAMETER
);
5196 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
5197 if (! NT_SUCCESS(Status
))
5199 SetLastNtError(Status
);
5206 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
5211 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
5214 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
5215 if (! NT_SUCCESS(Status
))
5217 SetLastNtError(Status
);
5237 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5239 Rect
->left
= MenuItem
->xItem
;
5240 Rect
->top
= MenuItem
->yItem
;
5241 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5242 Rect
->bottom
= MenuItem
->cyItem
;
5246 ERR("Failed Item Lookup! %u\n", uItem
);
5252 HWND hWnd
= Menu
->hWnd
;
5253 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5256 if (Menu
->fFlags
& MNF_POPUP
)
5258 XMove
= pWnd
->rcClient
.left
;
5259 YMove
= pWnd
->rcClient
.top
;
5263 XMove
= pWnd
->rcWindow
.left
;
5264 YMove
= pWnd
->rcWindow
.top
;
5267 Rect
->left
+= XMove
;
5269 Rect
->right
+= XMove
;
5270 Rect
->bottom
+= YMove
;
5275 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5277 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5278 HMENU hSysMenu
, hNewMenu
= NULL
;
5279 ROSMENUITEMINFO ItemInfoSet
= {0};
5280 ROSMENUITEMINFO ItemInfo
= {0};
5281 UNICODE_STRING MenuName
;
5283 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5284 if (NULL
== hSysMenu
)
5288 SysMenu
= UserGetMenuObject(hSysMenu
);
5289 if (NULL
== SysMenu
)
5291 UserDestroyMenu(hSysMenu
);
5295 SysMenu
->fFlags
|= MNF_SYSMENU
;
5296 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5300 //hNewMenu = co_IntLoadSysMenuTemplate();
5301 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5303 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5304 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5308 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5309 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5310 //ERR("%wZ\n",&MenuName);
5315 IntDestroyMenuObject(SysMenu
, FALSE
);
5318 Menu
= UserGetMenuObject(hNewMenu
);
5321 IntDestroyMenuObject(SysMenu
, FALSE
);
5325 // Do the rest in here.
5327 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5329 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5330 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5331 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5332 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5333 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5334 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5335 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5336 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5337 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5338 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5340 NewMenu
= IntCloneMenu(Menu
);
5341 if (NewMenu
== NULL
)
5343 IntDestroyMenuObject(Menu
, FALSE
);
5344 IntDestroyMenuObject(SysMenu
, FALSE
);
5348 IntReleaseMenuObject(NewMenu
);
5349 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5351 IntDestroyMenuObject(Menu
, FALSE
);
5359 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5361 if (Window
->pcls
->style
& CS_NOCLOSE
)
5362 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5364 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5365 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5366 ItemInfo
.fType
= MF_POPUP
;
5367 ItemInfo
.fState
= MFS_ENABLED
;
5368 ItemInfo
.dwTypeData
= NULL
;
5370 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5371 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5375 ERR("failed to load system menu!\n");
5380 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5386 if (Window
->SystemMenu
)
5388 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5389 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5391 IntDestroyMenuObject(Menu
, TRUE
);
5392 Window
->SystemMenu
= NULL
;
5398 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5399 if ((!Menu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5401 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5402 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5406 if (Window
->SystemMenu
)
5408 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5409 /* Store the dummy sysmenu handle to facilitate the refresh */
5410 /* of the close button if the SC_CLOSE item change */
5411 Menu
= UserGetMenuObject(hMenu
);
5414 Menu
->spwndNotify
= Window
;
5415 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5423 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5427 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5429 if (Window
->SystemMenu
)
5431 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5434 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5435 IntDestroyMenuObject(OldMenu
, TRUE
);
5439 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5441 { // Use spmenuSys too!
5442 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5445 Window
->SystemMenu
= NULL
;
5447 if (Menu
&& Window
!= Menu
->spwndNotify
)
5449 Menu
->spwndNotify
= Window
;
5461 PMENU OldMenu
, NewMenu
= NULL
;
5463 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5465 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5466 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5470 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5478 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5479 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5488 NewMenu
= IntGetMenuObject(Menu
);
5489 if (NULL
== NewMenu
)
5491 if (NULL
!= OldMenu
)
5493 IntReleaseMenuObject(OldMenu
);
5495 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5498 if (NULL
!= NewMenu
->hWnd
)
5500 /* Can't use the same menu for two windows */
5501 if (NULL
!= OldMenu
)
5503 IntReleaseMenuObject(OldMenu
);
5505 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5511 Wnd
->IDMenu
= (UINT_PTR
) Menu
;
5512 if (NULL
!= NewMenu
)
5514 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5515 IntReleaseMenuObject(NewMenu
);
5517 if (NULL
!= OldMenu
)
5519 OldMenu
->hWnd
= NULL
;
5520 IntReleaseMenuObject(OldMenu
);
5527 /* FUNCTIONS *****************************************************************/
5532 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5547 UserEnterExclusive();
5549 if(!(Window
= UserGetWindowObject(hwnd
)))
5551 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5556 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5563 Rect
.left
= leftBorder
;
5564 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5568 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5570 UserReleaseDC( 0, hdc
, FALSE
);
5581 NtUserCheckMenuItem(
5587 DECLARE_RETURN(DWORD
);
5589 TRACE("Enter NtUserCheckMenuItem\n");
5590 UserEnterExclusive();
5592 if(!(Menu
= UserGetMenuObject(hMenu
)))
5597 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5600 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5615 DECLARE_RETURN(BOOL
);
5617 TRACE("Enter NtUserDeleteMenu\n");
5618 UserEnterExclusive();
5620 if(!(Menu
= UserGetMenuObject(hMenu
)))
5625 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5628 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5634 * NtUserGetSystemMenu
5636 * The NtUserGetSystemMenu function allows the application to access the
5637 * window menu (also known as the system menu or the control menu) for
5638 * copying and modifying.
5642 * Handle to the window that will own a copy of the window menu.
5644 * Specifies the action to be taken. If this parameter is FALSE,
5645 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5646 * currently in use. The copy is initially identical to the window menu
5647 * but it can be modified.
5648 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5649 * to the default state. The previous window menu, if any, is destroyed.
5652 * If the bRevert parameter is FALSE, the return value is a handle to a
5653 * copy of the window menu. If the bRevert parameter is TRUE, the return
5661 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5665 DECLARE_RETURN(HMENU
);
5667 TRACE("Enter NtUserGetSystemMenu\n");
5668 UserEnterExclusive();
5670 if (!(Window
= UserGetWindowObject(hWnd
)))
5675 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5680 RETURN(Menu
->head
.h
);
5683 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5689 * NtUserSetSystemMenu
5696 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5698 BOOL Result
= FALSE
;
5701 DECLARE_RETURN(BOOL
);
5703 TRACE("Enter NtUserSetSystemMenu\n");
5704 UserEnterExclusive();
5706 if (!(Window
= UserGetWindowObject(hWnd
)))
5714 * Assign new menu handle and Up the Lock Count.
5716 if (!(Menu
= IntGetMenuObject(hMenu
)))
5721 Result
= IntSetSystemMenu(Window
, Menu
);
5724 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5729 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5738 NtUserGetTitleBarInfo(
5743 TITLEBARINFO bartitleinfo
;
5744 DECLARE_RETURN(BOOLEAN
);
5745 BOOLEAN retValue
= TRUE
;
5747 TRACE("Enter NtUserGetTitleBarInfo\n");
5748 UserEnterExclusive();
5750 /* Vaildate the windows handle */
5751 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5753 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5759 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5760 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5761 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5765 /* Fail copy the data */
5766 EngSetLastError(ERROR_INVALID_PARAMETER
);
5771 /* Get the tile bar info */
5774 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5779 /* Copy our buffer to user mode buffer bti */
5780 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5781 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5785 /* Fail copy the data */
5786 EngSetLastError(ERROR_INVALID_PARAMETER
);
5796 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5804 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5807 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5809 if(!(Menu
= UserGetMenuObject(hMenu
)))
5814 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5816 EngSetLastError(ERROR_ACCESS_DENIED
);
5819 return IntDestroyMenuObject(Menu
, FALSE
);
5830 DECLARE_RETURN(BOOL
);
5832 TRACE("Enter NtUserDestroyMenu\n");
5833 UserEnterExclusive();
5835 if(!(Menu
= UserGetMenuObject(hMenu
)))
5839 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5841 EngSetLastError(ERROR_ACCESS_DENIED
);
5844 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5847 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5856 NtUserEnableMenuItem(
5862 DECLARE_RETURN(UINT
);
5864 TRACE("Enter NtUserEnableMenuItem\n");
5865 UserEnterExclusive();
5867 if(!(Menu
= UserGetMenuObject(hMenu
)))
5872 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5875 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5887 TRACE("Enter NtUserEndMenu\n");
5888 UserEnterExclusive();
5889 /* if ( gptiCurrent->pMenuState &&
5890 gptiCurrent->pMenuState->pGlobalPopupMenu )
5892 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5895 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5898 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5900 if (fInsideMenuLoop
&& top_popup
)
5902 fInsideMenuLoop
= FALSE
;
5903 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5906 TRACE("Leave NtUserEndMenu\n");
5914 NtUserGetMenuBarInfo(
5924 PPOPUPMENU pPopupMenu
;
5925 USER_REFERENCE_ENTRY Ref
;
5926 NTSTATUS Status
= STATUS_SUCCESS
;
5928 DECLARE_RETURN(BOOL
);
5930 TRACE("Enter NtUserGetMenuBarInfo\n");
5933 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5935 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5939 UserRefObjectCo(pWnd
, &Ref
);
5941 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5943 kmbi
.hwndMenu
= NULL
;
5944 kmbi
.fBarFocused
= FALSE
;
5945 kmbi
.fFocused
= FALSE
;
5950 if (!pWnd
->pcls
->fnid
)
5952 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5954 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5955 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5958 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5959 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5960 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5961 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5963 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5965 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5970 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5971 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5972 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5975 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5976 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5977 hMenu
= UserHMGetHandle(Menu
);
5988 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5989 kmbi
.cbSize
= pmbi
->cbSize
;
5991 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5997 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5999 EngSetLastError(ERROR_INVALID_PARAMETER
);
6003 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
6007 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
6012 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
6013 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
6014 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
6015 TRACE("idItem a 0 %d\n",Ret
);
6019 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
6020 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
6024 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
6025 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
6028 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
6029 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
6031 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
6036 kmbi
.fFocused
= kmbi
.fBarFocused
;
6041 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
6042 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
6044 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6046 Status
= _SEH2_GetExceptionCode();
6050 if (!NT_SUCCESS(Status
))
6052 SetLastNtError(Status
);
6059 if (pWnd
) UserDerefObjectCo(pWnd
);
6060 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
6073 PMENU Menu
, SubMenu
;
6076 DECLARE_RETURN(UINT
);
6078 TRACE("Enter NtUserGetMenuIndex\n");
6081 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
6082 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
6085 MenuItem
= Menu
->rgItems
;
6086 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
6088 if (MenuItem
->spSubMenu
== SubMenu
)
6089 RETURN(MenuItem
->wID
);
6094 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
6103 NtUserGetMenuItemRect(
6114 NTSTATUS Status
= STATUS_SUCCESS
;
6115 DECLARE_RETURN(BOOL
);
6117 TRACE("Enter NtUserGetMenuItemRect\n");
6120 if (!(Menu
= UserGetMenuObject(hMenu
)))
6125 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
6127 Rect
.left
= MenuItem
->xItem
;
6128 Rect
.top
= MenuItem
->yItem
;
6129 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
6130 Rect
.bottom
= MenuItem
->cyItem
;
6140 if (lprcItem
== NULL
) RETURN( FALSE
);
6142 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
6144 if (Menu
->fFlags
& MNF_POPUP
)
6146 XMove
= ReferenceWnd
->rcClient
.left
;
6147 YMove
= ReferenceWnd
->rcClient
.top
;
6151 XMove
= ReferenceWnd
->rcWindow
.left
;
6152 YMove
= ReferenceWnd
->rcWindow
.top
;
6157 Rect
.right
+= XMove
;
6158 Rect
.bottom
+= YMove
;
6162 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
6164 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6166 Status
= _SEH2_GetExceptionCode();
6170 if (!NT_SUCCESS(Status
))
6172 SetLastNtError(Status
);
6178 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
6187 NtUserHiliteMenuItem(
6195 DECLARE_RETURN(BOOLEAN
);
6197 TRACE("Enter NtUserHiliteMenuItem\n");
6198 UserEnterExclusive();
6200 if(!(Window
= UserGetWindowObject(hWnd
)))
6202 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6206 if(!(Menu
= UserGetMenuObject(hMenu
)))
6208 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6212 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
6215 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
6225 NtUserDrawMenuBarTemp(
6235 NTSTATUS Status
= STATUS_SUCCESS
;
6236 DECLARE_RETURN(DWORD
);
6238 ERR("Enter NtUserDrawMenuBarTemp\n");
6239 UserEnterExclusive();
6241 if(!(Window
= UserGetWindowObject(hWnd
)))
6243 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6247 if(!(Menu
= UserGetMenuObject(hMenu
)))
6249 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6255 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6256 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6258 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6260 Status
= _SEH2_GetExceptionCode();
6264 if (Status
!= STATUS_SUCCESS
)
6266 SetLastNtError(Status
);
6270 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6273 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6282 NtUserMenuItemFromPoint(
6292 DECLARE_RETURN(int);
6294 TRACE("Enter NtUserMenuItemFromPoint\n");
6295 UserEnterExclusive();
6297 if (!(Menu
= UserGetMenuObject(hMenu
)))
6302 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6307 X
-= Window
->rcWindow
.left
;
6308 Y
-= Window
->rcWindow
.top
;
6311 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6315 Rect
.left
= mi
->xItem
;
6316 Rect
.top
= mi
->yItem
;
6317 Rect
.right
= mi
->cxItem
;
6318 Rect
.bottom
= mi
->cyItem
;
6320 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6322 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6328 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6331 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6351 UserEnterExclusive();
6353 if(!(Window
= UserGetWindowObject(hWnd
)))
6355 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6360 Rect
.left
= leftBorder
;
6361 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6365 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6382 DECLARE_RETURN(BOOL
);
6384 TRACE("Enter NtUserRemoveMenu\n");
6385 UserEnterExclusive();
6387 if(!(Menu
= UserGetMenuObject(hMenu
)))
6392 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6395 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6412 DECLARE_RETURN(BOOL
);
6414 TRACE("Enter NtUserSetMenu\n");
6415 UserEnterExclusive();
6417 if (!(Window
= UserGetWindowObject(hWnd
)))
6422 if (!IntSetMenu(Window
, Menu
, &Changed
))
6427 // Not minimized and please repaint!!!
6428 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6430 USER_REFERENCE_ENTRY Ref
;
6431 UserRefObjectCo(Window
, &Ref
);
6432 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6433 UserDerefObjectCo(Window
);
6439 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6448 NtUserSetMenuContextHelpId(
6450 DWORD dwContextHelpId
)
6453 DECLARE_RETURN(BOOL
);
6455 TRACE("Enter NtUserSetMenuContextHelpId\n");
6456 UserEnterExclusive();
6458 if(!(Menu
= UserGetMenuObject(hMenu
)))
6463 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6466 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6475 NtUserSetMenuDefaultItem(
6481 DECLARE_RETURN(BOOL
);
6483 TRACE("Enter NtUserSetMenuDefaultItem\n");
6484 UserEnterExclusive();
6486 if(!(Menu
= UserGetMenuObject(hMenu
)))
6491 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6494 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6503 NtUserSetMenuFlagRtoL(
6507 DECLARE_RETURN(BOOL
);
6509 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6510 UserEnterExclusive();
6512 if(!(Menu
= UserGetMenuObject(hMenu
)))
6517 RETURN(IntSetMenuFlagRtoL(Menu
));
6520 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6529 NtUserThunkedMenuInfo(
6534 DECLARE_RETURN(BOOL
);
6536 TRACE("Enter NtUserThunkedMenuInfo\n");
6537 UserEnterExclusive();
6539 if (!(Menu
= UserGetMenuObject(hMenu
)))
6544 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6547 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6556 NtUserThunkedMenuItemInfo(
6561 LPMENUITEMINFOW lpmii
,
6562 PUNICODE_STRING lpszCaption
)
6566 UNICODE_STRING lstrCaption
;
6567 DECLARE_RETURN(BOOL
);
6569 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6570 UserEnterExclusive();
6572 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6573 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6575 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6577 if (!(Menu
= UserGetMenuObject(hMenu
)))
6582 /* Check if we got a Caption */
6583 if (lpszCaption
&& lpszCaption
->Buffer
)
6585 /* Copy the string to kernel mode */
6586 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6589 if (!NT_SUCCESS(Status
))
6591 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6592 SetLastNtError(Status
);
6597 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6599 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6602 if (lstrCaption
.Buffer
)
6604 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6607 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6616 NtUserTrackPopupMenuEx(
6628 USER_REFERENCE_ENTRY Ref
;
6630 TRACE("Enter NtUserTrackPopupMenuEx\n");
6631 UserEnterExclusive();
6632 /* Parameter check */
6633 if (!(menu
= UserGetMenuObject( hMenu
)))
6635 ERR("TPME : Invalid Menu handle.\n");
6636 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6640 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6642 ERR("TPME : Invalid Window handle.\n");
6650 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6653 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6655 _SEH2_YIELD(goto Exit
);
6659 UserRefObjectCo(pWnd
, &Ref
);
6660 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6661 UserDerefObjectCo(pWnd
);
6664 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);