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 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
61 #define IS_SYSTEM_POPUP(MenuInfo) \
62 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
64 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
66 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
67 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
69 /* Maximum number of menu items a menu can contain */
70 #define MAX_MENU_ITEMS (0x4000)
71 #define MAX_GOINTOSUBMENU (0x10)
73 /* Space between 2 columns */
74 #define MENU_COL_SPACE 4
76 /* top and bottom margins for popup menus */
77 #define MENU_TOP_MARGIN 2 //3
78 #define MENU_BOTTOM_MARGIN 2
80 #define MENU_ITEM_HBMP_SPACE (5)
81 #define MENU_BAR_ITEMS_SPACE (12)
82 #define SEPARATOR_HEIGHT (5)
83 #define MENU_TAB_SPACE (8)
88 PMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
89 PMENU TopMenu
; /* initial menu */
90 PWND OwnerWnd
; /* where notifications are sent */
94 /* Internal MenuTrackMenu() flags */
95 #define TPM_INTERNAL 0xF0000000
96 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
97 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
102 #define UpdateMenuItemState(state, change) \
104 if((change) & MF_GRAYED) { \
105 (state) |= MF_GRAYED; \
107 (state) &= ~MF_GRAYED; \
108 } /* Separate the two for test_menu_resource_layout.*/ \
109 if((change) & MF_DISABLED) { \
110 (state) |= MF_DISABLED; \
112 (state) &= ~MF_DISABLED; \
114 if((change) & MFS_CHECKED) { \
115 (state) |= MFS_CHECKED; \
117 (state) &= ~MFS_CHECKED; \
119 if((change) & MFS_HILITE) { \
120 (state) |= MFS_HILITE; \
122 (state) &= ~MFS_HILITE; \
124 if((change) & MFS_DEFAULT) { \
125 (state) |= MFS_DEFAULT; \
127 (state) &= ~MFS_DEFAULT; \
129 if((change) & MF_MOUSESELECT) { \
130 (state) |= MF_MOUSESELECT; \
132 (state) &= ~MF_MOUSESELECT; \
138 DumpMenuItemList(PMENU Menu
, PITEM MenuItem
)
140 UINT cnt
= 0, i
= Menu
->cItems
;
143 if(MenuItem
->lpstr
.Length
)
144 DbgPrint(" %d. %wZ\n", ++cnt
, &MenuItem
->lpstr
);
146 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt
, (DWORD
)MenuItem
->lpstr
.Buffer
);
148 if(MFT_BITMAP
& MenuItem
->fType
)
149 DbgPrint("MFT_BITMAP ");
150 if(MFT_MENUBARBREAK
& MenuItem
->fType
)
151 DbgPrint("MFT_MENUBARBREAK ");
152 if(MFT_MENUBREAK
& MenuItem
->fType
)
153 DbgPrint("MFT_MENUBREAK ");
154 if(MFT_OWNERDRAW
& MenuItem
->fType
)
155 DbgPrint("MFT_OWNERDRAW ");
156 if(MFT_RADIOCHECK
& MenuItem
->fType
)
157 DbgPrint("MFT_RADIOCHECK ");
158 if(MFT_RIGHTJUSTIFY
& MenuItem
->fType
)
159 DbgPrint("MFT_RIGHTJUSTIFY ");
160 if(MFT_SEPARATOR
& MenuItem
->fType
)
161 DbgPrint("MFT_SEPARATOR ");
162 if(MFT_STRING
& MenuItem
->fType
)
163 DbgPrint("MFT_STRING ");
164 DbgPrint("\n fState=");
165 if(MFS_DISABLED
& MenuItem
->fState
)
166 DbgPrint("MFS_DISABLED ");
168 DbgPrint("MFS_ENABLED ");
169 if(MFS_CHECKED
& MenuItem
->fState
)
170 DbgPrint("MFS_CHECKED ");
172 DbgPrint("MFS_UNCHECKED ");
173 if(MFS_HILITE
& MenuItem
->fState
)
174 DbgPrint("MFS_HILITE ");
176 DbgPrint("MFS_UNHILITE ");
177 if(MFS_DEFAULT
& MenuItem
->fState
)
178 DbgPrint("MFS_DEFAULT ");
179 if(MFS_GRAYED
& MenuItem
->fState
)
180 DbgPrint("MFS_GRAYED ");
181 DbgPrint("\n wId=%d\n", MenuItem
->wID
);
185 DbgPrint("Entries: %d\n", cnt
);
190 #define FreeMenuText(Menu,MenuItem) \
192 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
193 (MenuItem)->lpstr.Length) { \
194 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
199 IntGetMenuObject(HMENU hMenu
)
201 PMENU Menu
= UserGetMenuObject(hMenu
);
203 Menu
->head
.cLockObj
++;
208 PMENU FASTCALL
VerifyMenu(PMENU pMenu
)
214 if (!pMenu
) return NULL
;
216 Error
= EngGetLastError();
220 hMenu
= UserHMGetHandle(pMenu
);
221 pItem
= pMenu
->rgItems
;
228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
230 ERR("Run away LOOP!\n");
231 EngSetLastError(Error
);
232 _SEH2_YIELD(return NULL
);
236 if ( UserObjectInDestroy(hMenu
))
238 ERR("Menu is marked for destruction!\n");
241 EngSetLastError(Error
);
247 IntIsMenu(HMENU Menu
)
249 if (UserGetMenuObject(Menu
)) return TRUE
;
255 IntGetMenu(HWND hWnd
)
257 PWND Wnd
= ValidateHwndNoErr(hWnd
);
262 return UserGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
265 PMENU
get_win_sys_menu( HWND hwnd
)
268 WND
*win
= ValidateHwndNoErr( hwnd
);
271 ret
= UserGetMenuObject(win
->SystemMenu
);
276 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
)
280 if (pMenu
->rgItems
) /* recursively destroy submenus */
283 ITEM
*item
= pMenu
->rgItems
;
284 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
286 SubMenu
= item
->spSubMenu
;
287 item
->spSubMenu
= NULL
;
289 /* Remove Item Text */
290 FreeMenuText(pMenu
,item
);
292 /* Remove Item Bitmap and set it for this process */
293 if (item
->hbmp
&& !(item
->fState
& MFS_HBMMENUBMP
))
295 GreSetObjectOwner(item
->hbmp
, GDI_OBJ_HMGR_POWNED
);
299 /* Remove Item submenu */
300 if (bRecurse
&& SubMenu
)//VerifyMenu(SubMenu))
302 /* Release submenu since it was referenced when inserted */
303 IntReleaseMenuObject(SubMenu
);
304 IntDestroyMenuObject(SubMenu
, bRecurse
);
308 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
309 pMenu
->rgItems
= NULL
;
315 /* Callback for the object manager */
317 UserDestroyMenuObject(PVOID Object
)
319 return IntDestroyMenuObject(Object
, TRUE
);
323 IntDestroyMenuObject(PMENU Menu
, BOOL bRecurse
)
330 /* Remove all menu items */
331 IntDestroyMenu( Menu
, bRecurse
);
333 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
338 Window
= ValidateHwndNoErr(Menu
->hWnd
);
341 //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
343 /* DestroyMenu should not destroy system menu popup owner */
344 if ((Menu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
)
346 // Should we check it to see if it has Class?
347 ERR("FIXME Pop up menu window thing'ie\n");
348 //co_UserDestroyWindow( Window );
353 if (UserObjectInDestroy(Menu
->head
.h
))
355 WARN("Menu already dead!\n");
358 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
360 { // Make sure it is really dead or just marked for deletion.
361 Error
= EngGetLastError();
362 ret
= UserObjectInDestroy(Menu
->head
.h
);
363 if (ret
&& EngGetLastError() == ERROR_INVALID_HANDLE
)
365 EngSetLastError(Error
);
368 } // See test_subpopup_locked_by_menu tests....
378 NONCLIENTMETRICSW ncm
;
380 /* get the menu font */
381 if (!ghMenuFont
|| !ghMenuFontBold
)
383 ncm
.cbSize
= sizeof(ncm
);
384 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
386 ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
390 ghMenuFont
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
391 if (ghMenuFont
== NULL
)
393 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
396 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
397 ghMenuFontBold
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
398 if (ghMenuFontBold
== NULL
)
400 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
401 GreDeleteObject(ghMenuFont
);
406 GreSetObjectOwner(ghMenuFont
, GDI_OBJ_HMGR_PUBLIC
);
407 GreSetObjectOwner(ghMenuFontBold
, GDI_OBJ_HMGR_PUBLIC
);
416 /**********************************************************************
419 * detect if there are loops in the menu tree (or the depth is too large)
421 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
427 if (!pmenu
) return depth
;
430 if( depth
> MAXMENUDEPTH
) return depth
;
431 item
= pmenu
->rgItems
;
433 for( i
= 0; i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
435 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
437 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
438 if( bdepth
> subdepth
) subdepth
= bdepth
;
440 if( subdepth
> MAXMENUDEPTH
)
441 TRACE("<- hmenu %p\n", item
->spSubMenu
);
447 /******************************************************************************
449 * UINT MenuGetStartOfNextColumn(
452 *****************************************************************************/
454 static UINT
MENU_GetStartOfNextColumn(
461 return NO_SELECTED_ITEM
;
464 if( i
== NO_SELECTED_ITEM
)
467 pItem
= menu
->rgItems
;
468 if (!pItem
) return NO_SELECTED_ITEM
;
470 for( ; i
< menu
->cItems
; ++i
) {
471 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
475 return NO_SELECTED_ITEM
;
478 /******************************************************************************
480 * UINT MenuGetStartOfPrevColumn(
483 *****************************************************************************/
484 static UINT
MENU_GetStartOfPrevColumn(
491 return NO_SELECTED_ITEM
;
493 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
494 return NO_SELECTED_ITEM
;
496 pItem
= menu
->rgItems
;
497 if (!pItem
) return NO_SELECTED_ITEM
;
499 /* Find the start of the column */
501 for(i
= menu
->iItem
; i
!= 0 &&
502 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
506 return NO_SELECTED_ITEM
;
508 for(--i
; i
!= 0; --i
) {
509 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
513 TRACE("ret %d.\n", i
);
518 /***********************************************************************
521 * Find a menu item. Return a pointer on the item, and modifies *hmenu
522 * in case the item was in a sub-menu.
524 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
527 ITEM
*fallback
= NULL
;
528 UINT fallback_pos
= 0;
531 if (!menu
) return NULL
;
533 if (wFlags
& MF_BYPOSITION
)
535 if (!menu
->cItems
) return NULL
;
536 if (*nPos
>= menu
->cItems
) return NULL
;
537 return &menu
->rgItems
[*nPos
];
541 PITEM item
= menu
->rgItems
;
542 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
546 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
547 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
553 else if (item
->wID
== *nPos
)
555 /* fallback to this item if nothing else found */
560 else if (item
->wID
== *nPos
)
569 *nPos
= fallback_pos
;
574 /***********************************************************************
577 * Find a Sub menu. Return the position of the submenu, and modifies
578 * *hmenu in case it is found in another sub-menu.
579 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
581 static UINT FASTCALL
MENU_FindSubMenu(PMENU
*menu
, PMENU SubTarget
)
586 item
= ((PMENU
)*menu
)->rgItems
;
587 for (i
= 0; i
< ((PMENU
)*menu
)->cItems
; i
++, item
++)
589 if (!item
->spSubMenu
)
593 if (item
->spSubMenu
== SubTarget
)
599 PMENU pSubMenu
= item
->spSubMenu
;
600 UINT pos
= MENU_FindSubMenu( &pSubMenu
, SubTarget
);
601 if (pos
!= NO_SELECTED_ITEM
)
609 return NO_SELECTED_ITEM
;
613 IntRemoveMenuItem( PMENU pMenu
, UINT nPos
, UINT wFlags
, BOOL bRecurse
)
617 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
618 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
622 FreeMenuText(pMenu
,item
);
623 if (bRecurse
&& item
->spSubMenu
)
625 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
);
627 ////// Use cAlloced with inc's of 8's....
628 if (--pMenu
->cItems
== 0)
630 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
631 pMenu
->rgItems
= NULL
;
635 while(nPos
< pMenu
->cItems
)
641 pMenu
->rgItems
= DesktopHeapReAlloc(pMenu
->head
.rpdesk
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
646 /**********************************************************************
649 * Insert (allocate) a new item into a menu.
651 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
655 /* Find where to insert new item */
657 if (flags
& MF_BYPOSITION
) {
658 if (pos
> menu
->cItems
)
661 if (!MENU_FindItem( &menu
, &pos
, flags
))
663 if (submenu
) *submenu
= menu
;
664 if (npos
) *npos
= pos
;
669 /* Make sure that MDI system buttons stay on the right side.
670 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
671 * regardless of their id.
674 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
675 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
678 TRACE("inserting at %u flags %x\n", pos
, flags
);
680 /* Create new items array */
682 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
685 WARN("allocation failed\n" );
688 if (menu
->cItems
> 0)
690 /* Copy the old array into the new one */
691 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
692 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
693 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
695 menu
->rgItems
= newItems
;
697 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
698 menu
->cyMenu
= 0; /* force size recalculate */
699 return &newItems
[pos
];
704 _In_ PMENU MenuObject
,
707 PROSMENUITEMINFO ItemInfo
,
708 PUNICODE_STRING lpstr
)
711 PMENU SubMenu
= NULL
;
713 NT_ASSERT(MenuObject
!= NULL
);
715 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
717 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
721 SubMenu
= MenuObject
;
723 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
725 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
727 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
731 /* Force size recalculation! */
733 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
735 TRACE("IntInsertMenuItemToList = %u %i\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
742 _Out_ PHANDLE Handle
,
744 _In_ PDESKTOP Desktop
,
745 _In_ PPROCESSINFO ppi
)
749 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
761 Menu
->cyMax
= 0; /* Default */
762 Menu
->hbrBack
= NULL
; /* No brush */
763 Menu
->dwContextHelpId
= 0; /* Default */
764 Menu
->dwMenuData
= 0; /* Default */
765 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
766 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
767 Menu
->spwndNotify
= NULL
;
768 Menu
->cyMenu
= 0; // Height
769 Menu
->cxMenu
= 0; // Width
770 Menu
->cItems
= 0; // Item count
773 Menu
->cxTextAlign
= 0;
774 Menu
->rgItems
= NULL
;
777 Menu
->TimeToHide
= FALSE
;
783 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
785 PITEM MenuItem
, NewMenuItem
= NULL
;
791 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, (Source
->cItems
+1) * sizeof(ITEM
));
792 if(!NewMenuItem
) return FALSE
;
794 RtlZeroMemory(NewMenuItem
, (Source
->cItems
+1) * sizeof(ITEM
));
796 Destination
->rgItems
= NewMenuItem
;
798 MenuItem
= Source
->rgItems
;
799 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
801 NewMenuItem
->fType
= MenuItem
->fType
;
802 NewMenuItem
->fState
= MenuItem
->fState
;
803 NewMenuItem
->wID
= MenuItem
->wID
;
804 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
805 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
806 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
807 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
808 if (MenuItem
->lpstr
.Length
)
810 NewMenuItem
->lpstr
.Length
= 0;
811 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
812 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
813 if (!NewMenuItem
->lpstr
.Buffer
)
815 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
818 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
819 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
820 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
824 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
825 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
827 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
833 IntCloneMenu(PMENU Source
)
841 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
842 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
844 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
851 Menu
->fFlags
= Source
->fFlags
;
852 Menu
->cyMax
= Source
->cyMax
;
853 Menu
->hbrBack
= Source
->hbrBack
;
854 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
855 Menu
->dwMenuData
= Source
->dwMenuData
;
856 Menu
->iItem
= NO_SELECTED_ITEM
;
857 Menu
->spwndNotify
= NULL
;
860 Menu
->cItems
= Source
->cItems
;
863 Menu
->cxTextAlign
= 0;
864 Menu
->rgItems
= NULL
;
867 Menu
->TimeToHide
= FALSE
;
869 IntCloneMenuItems(Menu
, Source
);
875 IntSetMenuFlagRtoL(PMENU Menu
)
877 ERR("SetMenuFlagRtoL\n");
878 Menu
->fFlags
|= MNF_RTOL
;
883 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
885 Menu
->dwContextHelpId
= dwContextHelpId
;
890 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
892 if(lpmi
->fMask
& MIM_BACKGROUND
)
893 lpmi
->hbrBack
= Menu
->hbrBack
;
894 if(lpmi
->fMask
& MIM_HELPID
)
895 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
896 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
897 lpmi
->cyMax
= Menu
->cyMax
;
898 if(lpmi
->fMask
& MIM_MENUDATA
)
899 lpmi
->dwMenuData
= Menu
->dwMenuData
;
900 if(lpmi
->fMask
& MIM_STYLE
)
901 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
903 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
905 lpmi
->cItems
= Menu
->cItems
;
907 lpmi
->iItem
= Menu
->iItem
;
908 lpmi
->cxMenu
= Menu
->cxMenu
;
909 lpmi
->cyMenu
= Menu
->cyMenu
;
910 lpmi
->spwndNotify
= Menu
->spwndNotify
;
911 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
912 lpmi
->iTop
= Menu
->iTop
;
913 lpmi
->iMaxTop
= Menu
->iMaxTop
;
914 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
916 lpmi
->fFlags
= Menu
->fFlags
;
917 lpmi
->Self
= Menu
->head
.h
;
918 lpmi
->TimeToHide
= Menu
->TimeToHide
;
919 lpmi
->Wnd
= Menu
->hWnd
;
925 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
927 if(lpmi
->fMask
& MIM_BACKGROUND
)
928 Menu
->hbrBack
= lpmi
->hbrBack
;
929 if(lpmi
->fMask
& MIM_HELPID
)
930 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
931 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
932 Menu
->cyMax
= lpmi
->cyMax
;
933 if(lpmi
->fMask
& MIM_MENUDATA
)
934 Menu
->dwMenuData
= lpmi
->dwMenuData
;
935 if(lpmi
->fMask
& MIM_STYLE
)
936 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
937 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
940 PITEM item
= Menu
->rgItems
;
941 for ( i
= Menu
->cItems
; i
; i
--, item
++)
943 if ( item
->spSubMenu
)
945 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
949 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
951 Menu
->iItem
= lpmi
->iItem
;
952 Menu
->cyMenu
= lpmi
->cyMenu
;
953 Menu
->cxMenu
= lpmi
->cxMenu
;
954 Menu
->spwndNotify
= lpmi
->spwndNotify
;
955 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
956 Menu
->iTop
= lpmi
->iTop
;
957 Menu
->iMaxTop
= lpmi
->iMaxTop
;
958 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
960 Menu
->TimeToHide
= lpmi
->TimeToHide
;
961 Menu
->hWnd
= lpmi
->Wnd
;
963 if ( lpmi
->fMask
& MIM_STYLE
)
965 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
966 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
967 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
973 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
974 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
978 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
980 lpmii
->fType
= MenuItem
->fType
;
982 if(lpmii
->fMask
& MIIM_BITMAP
)
984 lpmii
->hbmpItem
= MenuItem
->hbmp
;
986 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
988 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
989 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
991 if(lpmii
->fMask
& MIIM_DATA
)
993 lpmii
->dwItemData
= MenuItem
->dwItemData
;
995 if(lpmii
->fMask
& MIIM_ID
)
997 lpmii
->wID
= MenuItem
->wID
;
999 if(lpmii
->fMask
& MIIM_STATE
)
1001 lpmii
->fState
= MenuItem
->fState
;
1003 if(lpmii
->fMask
& MIIM_SUBMENU
)
1005 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
1008 if ((lpmii
->fMask
& MIIM_STRING
) ||
1009 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1011 if (lpmii
->dwTypeData
== NULL
)
1013 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1016 { //// lpmii->lpstr can be read in user mode!!!!
1017 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1018 min(lpmii
->cch
* sizeof(WCHAR
),
1019 MenuItem
->lpstr
.MaximumLength
));
1020 if (! NT_SUCCESS(Status
))
1022 SetLastNtError(Status
);
1028 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1030 lpmii
->Rect
.left
= MenuItem
->xItem
;
1031 lpmii
->Rect
.top
= MenuItem
->yItem
;
1032 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1033 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1034 lpmii
->dxTab
= MenuItem
->dxTab
;
1035 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1036 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1037 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1044 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1046 PMENU SubMenuObject
;
1047 BOOL circref
= FALSE
;
1049 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1053 if ( lpmii
->fMask
& MIIM_FTYPE
)
1055 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1056 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1058 if (lpmii
->fMask
& MIIM_TYPE
)
1060 #if 0 //// Done in User32.
1061 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1063 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1064 KeRosDumpStackFrames(NULL
, 20);
1065 /* This does not happen on Win9x/ME */
1066 SetLastNtError( ERROR_INVALID_PARAMETER
);
1071 * Delete the menu item type when changing type from
1074 if (MenuItem
->fType
!= lpmii
->fType
&&
1075 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1077 FreeMenuText(MenuObject
,MenuItem
);
1078 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1079 MenuItem
->Xlpstr
= NULL
;
1081 if(lpmii
->fType
& MFT_BITMAP
)
1084 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1086 { /* Win 9x/Me stuff */
1087 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1089 lpmii
->dwTypeData
= 0;
1092 if(lpmii
->fMask
& MIIM_BITMAP
)
1094 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1095 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1096 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1098 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1100 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1102 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1103 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1105 if(lpmii
->fMask
& MIIM_DATA
)
1107 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1109 if(lpmii
->fMask
& MIIM_ID
)
1111 MenuItem
->wID
= lpmii
->wID
;
1113 if(lpmii
->fMask
& MIIM_STATE
)
1115 /* Remove MFS_DEFAULT flag from all other menu items if this item
1116 has the MFS_DEFAULT state */
1117 if(lpmii
->fState
& MFS_DEFAULT
)
1118 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1119 /* Update the menu item state flags */
1120 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1123 if(lpmii
->fMask
& MIIM_SUBMENU
)
1125 if (lpmii
->hSubMenu
)
1127 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1128 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1130 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1132 if (MenuObject
== SubMenuObject
)
1135 ERR("Pop Up Menu Double Trouble!\n");
1136 SubMenuObject
= IntCreateMenu(&hMenu
,
1138 MenuObject
->head
.rpdesk
,
1139 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1140 if (!SubMenuObject
) return FALSE
;
1141 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1144 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1146 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1147 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1150 /* Make sure the submenu is marked as a popup menu */
1151 SubMenuObject
->fFlags
|= MNF_POPUP
;
1152 // Now fix the test_subpopup_locked_by_menu tests....
1153 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1154 MenuItem
->spSubMenu
= SubMenuObject
;
1155 UserReferenceObject(SubMenuObject
);
1159 EngSetLastError( ERROR_INVALID_PARAMETER
);
1164 { // If submenu just dereference it.
1165 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1166 MenuItem
->spSubMenu
= NULL
;
1170 if ((lpmii
->fMask
& MIIM_STRING
) ||
1171 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1173 /* free the string when used */
1174 FreeMenuText(MenuObject
,MenuItem
);
1175 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1176 MenuItem
->Xlpstr
= NULL
;
1178 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1180 UNICODE_STRING Source
;
1182 Source
.Length
= Source
.MaximumLength
= lpmii
->cch
* sizeof(WCHAR
);
1183 Source
.Buffer
= lpmii
->dwTypeData
;
1185 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1186 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1188 MenuItem
->lpstr
.Length
= 0;
1189 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1190 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1191 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1193 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1194 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1199 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1200 !MenuItem
->Xlpstr
&&
1201 !lpmii
->dwTypeData
&&
1202 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1204 MenuItem
->fType
|= MFT_SEPARATOR
;
1206 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1208 MenuItem
->xItem
= lpmii
->Rect
.left
;
1209 MenuItem
->yItem
= lpmii
->Rect
.top
;
1210 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1211 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1212 MenuItem
->dxTab
= lpmii
->dxTab
;
1213 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1214 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1215 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1223 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1228 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1230 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1232 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1234 /* If the close item in the system menu change update the close button */
1237 switch (MenuItem
->wID
) // More than just close.
1245 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1247 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1249 /* Refresh the frame to reflect the change */
1250 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1252 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1255 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1265 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1270 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1272 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1274 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1280 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1283 PITEM MenuItem
= MenuObject
->rgItems
;
1285 if (!MenuItem
) return FALSE
;
1287 /* reset all default-item flags */
1288 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1290 MenuItem
->fState
&= ~MFS_DEFAULT
;
1293 /* no default item */
1294 if(uItem
== (UINT
)-1)
1298 MenuItem
= MenuObject
->rgItems
;
1301 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1302 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1307 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1309 if (MenuItem
->wID
== uItem
)
1311 MenuItem
->fState
|= MFS_DEFAULT
;
1321 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1324 PITEM MenuItem
= MenuObject
->rgItems
;
1327 if (!MenuItem
) return -1;
1329 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1332 if (i
>= MenuObject
->cItems
) return -1;
1335 /* default: don't return disabled items */
1336 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1338 /* search rekursiv when needed */
1339 if ( (MenuItem
->fType
& MF_POPUP
) && (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1343 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1345 if ( -1 != ret
) return ret
;
1347 /* when item not found in submenu, return the popup item */
1349 return ( fByPos
) ? i
: MenuItem
->wID
;
1359 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1360 return pItem
->spSubMenu
;
1363 /***********************************************************************
1364 * MenuInitSysMenuPopup
1366 * Grey the appropriate items in System menu.
1368 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1373 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1374 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1375 gray
= ((style
& WS_MAXIMIZE
) != 0);
1376 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1377 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1378 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1379 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1380 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1381 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1382 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1383 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1385 /* The menu item must keep its state if it's disabled */
1387 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1389 /* Set default menu item */
1390 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1391 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1392 else DefItem
= SC_CLOSE
;
1394 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1398 /***********************************************************************
1399 * MenuDrawPopupGlyph
1401 * Draws popup magic glyphs (can be found in system menu).
1403 static void FASTCALL
1404 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1407 HFONT hFont
, hOldFont
;
1413 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1416 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1419 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1422 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1426 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1429 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1430 RECTL_vInflateRect(r
, -2, -2);
1431 lf
.lfHeight
= r
->bottom
- r
->top
;
1433 lf
.lfWeight
= FW_NORMAL
;
1434 lf
.lfCharSet
= DEFAULT_CHARSET
;
1435 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1436 hFont
= GreCreateFontIndirectW(&lf
);
1437 /* save font and text color */
1438 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1439 clrsave
= GreGetTextColor(dc
);
1440 bkmode
= GreGetBkMode(dc
);
1441 /* set color and drawing mode */
1442 IntGdiSetBkMode(dc
, TRANSPARENT
);
1448 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1449 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1452 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1453 /* draw selected symbol */
1454 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1455 /* restore previous settings */
1456 IntGdiSetTextColor(dc
, clrsave
);
1457 NtGdiSelectFont(dc
, hOldFont
);
1458 IntGdiSetBkMode(dc
, bkmode
);
1459 GreDeleteObject(hFont
);
1462 /***********************************************************************
1463 * MENU_AdjustMenuItemRect
1465 * Adjust menu item rectangle according to scrolling state.
1468 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1470 if (menu
->dwArrowsOn
)
1472 UINT arrow_bitmap_height
;
1473 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1474 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1475 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1479 /***********************************************************************
1480 * MENU_FindItemByCoords
1482 * Find the item at the specified coordinates (screen coords). Does
1483 * not work for child windows and therefore should not be called for
1484 * an arbitrary system menu.
1486 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1491 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1493 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
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;
1664 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1667 /* Check if there is a magic menu item associated with this item */
1668 if (IS_MAGIC_BITMAP(hbmToDraw
))
1674 switch ((INT_PTR
)hbmToDraw
)
1676 case (INT_PTR
)HBMMENU_SYSTEM
:
1677 if (lpitem
->dwItemData
)
1679 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1681 ERR("Get Item Data from this Window!!!\n");
1684 ERR("Draw Bitmap\n");
1685 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1686 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1690 PCURICON_OBJECT pIcon
= NULL
;
1691 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1693 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1694 /* only use right half of the bitmap */
1695 //bmp_xoffset = bm.bmWidth / 2;
1696 //bm.bmWidth -= bmp_xoffset;
1699 pIcon
= NC_IconForWindow(WndOwner
);
1700 // FIXME: NC_IconForWindow should reference it for us */
1701 if (pIcon
) UserReferenceObject(pIcon
);
1706 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1707 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1708 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1709 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1710 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1711 UserDereferenceObject(pIcon
);
1716 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1717 flags
= DFCS_CAPTIONRESTORE
;
1719 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1721 flags
= DFCS_CAPTIONMIN
;
1723 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1725 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1727 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1728 flags
= DFCS_CAPTIONCLOSE
;
1730 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1731 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1733 case (INT_PTR
)HBMMENU_CALLBACK
:
1735 DRAWITEMSTRUCT drawItem
;
1737 drawItem
.CtlType
= ODT_MENU
;
1739 drawItem
.itemID
= lpitem
->wID
;
1740 drawItem
.itemAction
= odaction
;
1741 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1742 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1743 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1744 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1745 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1746 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1747 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1748 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1750 drawItem
.rcItem
= *rect
;
1751 drawItem
.itemData
= lpitem
->dwItemData
;
1752 /* some applications make this assumption on the DC's origin */
1753 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1754 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1755 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1756 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1761 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1762 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1763 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1764 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1765 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1768 RECTL_vInflateRect(&r
, -1, -1);
1769 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1770 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1774 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1777 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1778 NtGdiSelectBitmap( hdcMem
, bmp
);
1779 /* handle fontsize > bitmap_height */
1780 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1782 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1783 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1784 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1785 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1786 IntGdiDeleteDC( hdcMem
, FALSE
);
1790 IntGetDialogBaseUnits(VOID
)
1799 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1801 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1802 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1803 UserReleaseDC( 0, hdc
, FALSE
);
1810 /***********************************************************************
1813 * Calculate the size of the menu item and store it in lpitem->rect.
1815 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1816 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1819 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1820 UINT arrow_bitmap_width
;
1824 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1826 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1828 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1830 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1832 if (lpitem
->fType
& MF_OWNERDRAW
)
1834 MEASUREITEMSTRUCT mis
;
1835 mis
.CtlType
= ODT_MENU
;
1837 mis
.itemID
= lpitem
->wID
;
1838 mis
.itemData
= lpitem
->dwItemData
;
1839 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1841 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1842 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1843 * width of a menufont character to the width of an owner-drawn menu.
1845 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1847 /* under at least win95 you seem to be given a standard
1848 height for the menu and the height value is ignored */
1849 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1851 Rect
.bottom
+= mis
.itemHeight
;
1853 //lpitem->cxBmp = mis.itemWidth;
1854 //lpitem->cyBmp = mis.itemHeight;
1855 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1856 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1857 lpitem
->wID
, Rect
.right
-Rect
.left
,
1858 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1860 lpitem
->xItem
= Rect
.left
;
1861 lpitem
->yItem
= Rect
.top
;
1862 lpitem
->cxItem
= Rect
.right
;
1863 lpitem
->cyItem
= Rect
.bottom
;
1868 lpitem
->xItem
= orgX
;
1869 lpitem
->yItem
= orgY
;
1870 lpitem
->cxItem
= orgX
;
1871 lpitem
->cyItem
= orgY
;
1873 if (lpitem
->fType
& MF_SEPARATOR
)
1875 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1877 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1888 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1889 /* Keep the size of the bitmap in callback mode to be able
1890 * to draw it correctly */
1891 lpitem
->cxBmp
= size
.cx
;
1892 lpitem
->cyBmp
= size
.cy
;
1893 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1894 lpitem
->cxItem
+= size
.cx
+ 2;
1895 itemheight
= size
.cy
+ 2;
1897 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1898 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1899 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1900 lpitem
->dxTab
= lpitem
->cxItem
;
1901 lpitem
->cxItem
+= arrow_bitmap_width
;
1902 } else /* hbmpItem & MenuBar */ {
1903 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1904 lpitem
->cxItem
+= size
.cx
;
1905 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1906 itemheight
= size
.cy
;
1908 /* Special case: Minimize button doesn't have a space behind it. */
1909 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1910 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1911 lpitem
->cxItem
-= 1;
1914 else if (!menuBar
) {
1915 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1916 lpitem
->cxItem
+= check_bitmap_width
;
1917 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1918 lpitem
->dxTab
= lpitem
->cxItem
;
1919 lpitem
->cxItem
+= arrow_bitmap_width
;
1922 /* it must be a text item - unless it's the system menu */
1923 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1924 HFONT hfontOld
= NULL
;
1925 RECT rc
;// = lpitem->Rect;
1926 LONG txtheight
, txtwidth
;
1928 rc
.left
= lpitem
->xItem
;
1929 rc
.top
= lpitem
->yItem
;
1930 rc
.right
= lpitem
->cxItem
; // Do this for now......
1931 rc
.bottom
= lpitem
->cyItem
;
1933 if ( lpitem
->fState
& MFS_DEFAULT
) {
1934 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1937 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1939 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1940 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1942 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1944 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1947 int n
= (int)( p
- lpitem
->Xlpstr
);
1948 /* Item contains a tab (only meaningful in popup menus) */
1949 /* get text size before the tab */
1950 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1951 DT_SINGLELINE
|DT_CALCRECT
);
1952 txtwidth
= rc
.right
- rc
.left
;
1953 p
+= 1; /* advance past the Tab */
1954 /* get text size after the tab */
1955 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1956 DT_SINGLELINE
|DT_CALCRECT
);
1957 lpitem
->dxTab
+= txtwidth
;
1958 txtheight
= max( txtheight
, tmpheight
);
1959 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1960 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1962 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1963 DT_SINGLELINE
|DT_CALCRECT
);
1964 txtwidth
= rc
.right
- rc
.left
;
1965 lpitem
->dxTab
+= txtwidth
;
1967 lpitem
->cxItem
+= 2 + txtwidth
;
1968 itemheight
= max( itemheight
,
1969 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1973 NtGdiSelectFont (hdc
, hfontOld
);
1975 } else if( menuBar
) {
1976 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1978 lpitem
->cyItem
+= itemheight
;
1979 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1982 /***********************************************************************
1983 * MENU_GetMaxPopupHeight
1986 MENU_GetMaxPopupHeight(PMENU lppop
)
1990 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1991 return lppop
->cyMax
;
1993 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
1994 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
1997 /***********************************************************************
1998 * MenuPopupMenuCalcSize
2000 * Calculate the size of a popup menu.
2002 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
2007 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
2008 BOOL textandbmp
= FALSE
;
2010 Menu
->cxMenu
= Menu
->cyMenu
= 0;
2011 if (Menu
->cItems
== 0) return;
2013 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2015 NtGdiSelectFont( hdc
, ghMenuFont
);
2020 Menu
->cxTextAlign
= 0;
2022 while (start
< Menu
->cItems
)
2024 lpitem
= &Menu
->rgItems
[start
];
2026 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2027 orgX
+= MENU_COL_SPACE
;
2028 orgY
= MENU_TOP_MARGIN
;
2030 maxTab
= maxTabWidth
= 0;
2031 /* Parse items until column break or end of menu */
2032 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2035 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2037 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2038 maxX
= max(maxX
, lpitem
->cxItem
);
2039 orgY
= lpitem
->cyItem
;
2040 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2042 maxTab
= max( maxTab
, lpitem
->dxTab
);
2043 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2045 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2048 /* Finish the column (set all items to the largest width found) */
2049 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2050 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2052 lpitem
->cxItem
= maxX
;
2053 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2054 lpitem
->dxTab
= maxTab
;
2056 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2059 Menu
->cxMenu
= maxX
;
2060 /* if none of the items have both text and bitmap then
2061 * the text and bitmaps are all aligned on the left. If there is at
2062 * least one item with both text and bitmap then bitmaps are
2063 * on the left and texts left aligned with the right hand side
2065 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2067 /* space for 3d border */
2068 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2071 /* Adjust popup height if it exceeds maximum */
2072 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2073 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2074 if (Menu
->cyMenu
>= maxHeight
)
2076 Menu
->cyMenu
= maxHeight
;
2077 Menu
->dwArrowsOn
= 1;
2081 Menu
->dwArrowsOn
= 0;
2083 UserReleaseDC( 0, hdc
, FALSE
);
2086 /***********************************************************************
2087 * MENU_MenuBarCalcSize
2089 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2090 * height is off by 1 pixel which causes lengthy window relocations when
2091 * active document window is maximized/restored.
2093 * Calculate the size of the menu bar.
2095 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2098 UINT start
, i
, helpPos
;
2099 int orgX
, orgY
, maxY
;
2101 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2102 if (lppop
->cItems
== 0) return;
2103 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2104 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2106 maxY
= lprect
->top
+1;
2109 lppop
->cxTextAlign
= 0;
2110 while (start
< lppop
->cItems
)
2112 lpitem
= &lppop
->rgItems
[start
];
2113 orgX
= lprect
->left
;
2116 /* Parse items until line break or end of menu */
2117 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2119 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2121 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2123 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2124 //debug_print_menuitem (" item: ", lpitem, "");
2125 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2126 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2128 if (lpitem
->cxItem
> lprect
->right
)
2130 if (i
!= start
) break;
2131 else lpitem
->cxItem
= lprect
->right
;
2133 maxY
= max( maxY
, lpitem
->cyItem
);
2134 orgX
= lpitem
->cxItem
;
2137 /* Finish the line (set all items to the largest height found) */
2139 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2140 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2142 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2144 start
= i
; /* This works! */
2147 lprect
->bottom
= maxY
;
2148 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2150 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2151 /* the last item (if several lines, only move the last line) */
2152 if (helpPos
== ~0U) return;
2153 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2154 orgY
= lpitem
->yItem
;
2155 orgX
= lprect
->right
;
2156 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2157 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2158 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2159 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2160 lpitem
->cxItem
= orgX
;
2161 orgX
= lpitem
->xItem
;
2165 /***********************************************************************
2166 * MENU_DrawScrollArrows
2168 * Draw scroll arrows.
2170 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2172 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2176 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2177 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2181 rect
.right
= lppop
->cxMenu
;
2182 rect
.bottom
= arrow_bitmap_height
;
2183 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2184 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2186 dfcrc
.right
= arrow_bitmap_width
;
2187 dfcrc
.bottom
= arrow_bitmap_height
;
2188 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2190 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2191 rect
.bottom
= lppop
->cyMenu
;
2192 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2193 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2194 Flags
= DFCS_INACTIVE
;
2195 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2196 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2197 dfcrc
.right
= arrow_bitmap_width
;
2198 dfcrc
.bottom
= lppop
->cyMenu
;
2199 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2202 /***********************************************************************
2205 * Draw a single menu item.
2207 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2208 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2212 BOOL flat_menu
= FALSE
;
2214 UINT arrow_bitmap_width
= 0;
2217 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2220 if (lpitem
->fType
& MF_SYSMENU
)
2222 if ( (Wnd
->style
& WS_MINIMIZE
))
2224 NC_GetInsideRect(Wnd
, &rect
);
2225 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2230 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2231 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2235 if (lpitem
->fState
& MF_HILITE
)
2237 if(menuBar
&& !flat_menu
) {
2238 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2239 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2241 if (lpitem
->fState
& MF_GRAYED
)
2242 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2244 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2245 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2250 if (lpitem
->fState
& MF_GRAYED
)
2251 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2253 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2254 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2257 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2258 //rect = lpitem->Rect;
2259 rect
.left
= lpitem
->xItem
;
2260 rect
.top
= lpitem
->yItem
;
2261 rect
.right
= lpitem
->cxItem
; // Do this for now......
2262 rect
.bottom
= lpitem
->cyItem
;
2264 MENU_AdjustMenuItemRect(Menu
, &rect
);
2266 if (lpitem
->fType
& MF_OWNERDRAW
)
2269 ** Experimentation under Windows reveals that an owner-drawn
2270 ** menu is given the rectangle which includes the space it requested
2271 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2272 ** and a popup-menu arrow. This is the value of lpitem->rect.
2273 ** Windows will leave all drawing to the application except for
2274 ** the popup-menu arrow. Windows always draws that itself, after
2275 ** the menu owner has finished drawing.
2278 COLORREF old_bk
, old_text
;
2280 dis
.CtlType
= ODT_MENU
;
2282 dis
.itemID
= lpitem
->wID
;
2283 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2285 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2286 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2287 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2288 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2289 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2290 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2291 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2292 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2293 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2296 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2297 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2298 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2299 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2301 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2302 old_bk
= GreGetBkColor(hdc
);
2303 old_text
= GreGetTextColor(hdc
);
2304 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2305 IntGdiSetBkColor(hdc
, old_bk
);
2306 IntGdiSetTextColor(hdc
, old_text
);
2307 /* Draw the popup-menu arrow */
2308 if (!menuBar
&& lpitem
->spSubMenu
)
2311 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2312 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2313 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2318 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2320 if (lpitem
->fState
& MF_HILITE
)
2324 RECTL_vInflateRect (&rect
, -1, -1);
2325 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2326 RECTL_vInflateRect (&rect
, 1, 1);
2327 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2332 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2334 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2338 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2340 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2342 /* vertical separator */
2343 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2348 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2350 rc
.bottom
= Height
- 3;
2353 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2354 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2355 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2356 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2357 NtGdiSelectPen( hdc
, oldPen
);
2360 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2363 /* horizontal separator */
2364 if (lpitem
->fType
& MF_SEPARATOR
)
2371 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
2374 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2375 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2376 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2377 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2378 NtGdiSelectPen( hdc
, oldPen
);
2381 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2386 /* helper lines for debugging */
2387 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2388 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2389 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2390 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2391 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2392 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2398 INT y
= rect
.top
+ rect
.bottom
;
2400 BOOL checked
= FALSE
;
2401 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2402 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2403 /* Draw the check mark
2406 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2408 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2409 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2410 lpitem
->hbmpUnchecked
;
2411 if (bm
) /* we have a custom bitmap */
2413 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2415 NtGdiSelectBitmap( hdcMem
, bm
);
2416 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2417 check_bitmap_width
, check_bitmap_height
,
2418 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2419 IntGdiDeleteDC( hdcMem
, FALSE
);
2422 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2426 r
.right
= r
.left
+ UserGetSystemMetrics(SM_CXMENUCHECK
);
2427 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2428 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2429 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2433 if ( lpitem
->hbmp
)//&& !( checked && (Menu->dwStyle & MNS_CHECKORBMP)))
2436 //CopyRect(&bmpRect, &rect);
2438 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2439 bmpRect
.left
+= check_bitmap_width
+ 2;
2440 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2443 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2444 /* some applications make this assumption on the DC's origin */
2445 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
2446 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2447 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
2450 /* Draw the popup-menu arrow */
2451 if (lpitem
->spSubMenu
)
2454 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2455 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2456 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2459 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2460 rect
.left
+= check_bitmap_width
;
2461 rect
.right
-= arrow_bitmap_width
;//check_bitmap_width;
2463 else if( lpitem
->hbmp
)
2464 { /* Draw the bitmap */
2467 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
2468 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
, Menu
, WndOwner
, odaction
, menuBar
);
2469 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
2472 /* process text if present */
2478 UINT uFormat
= menuBar
?
2479 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2480 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2482 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2483 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2485 rect
.left
+= Menu
->cxTextAlign
;
2487 if ( lpitem
->fState
& MFS_DEFAULT
)
2489 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2494 rect
.left
+= lpitem
->cxBmp
;
2495 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2496 rect
.left
+= MenuCharSize
.cx
;
2497 rect
.right
-= MenuCharSize
.cx
;
2498 //rect.left += MENU_BAR_ITEMS_SPACE / 2;
2499 //rect.right -= MENU_BAR_ITEMS_SPACE / 2;
2502 Text
= lpitem
->Xlpstr
;
2505 for (i
= 0; L
'\0' != Text
[i
]; i
++)
2506 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2510 if(lpitem
->fState
& MF_GRAYED
)
2512 if (!(lpitem
->fState
& MF_HILITE
) )
2514 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2515 IntGdiSetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
2516 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2517 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2519 IntGdiSetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
2521 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2523 /* paint the shortcut text */
2524 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2526 if (L
'\t' == Text
[i
])
2528 rect
.left
= lpitem
->dxTab
;
2529 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2533 rect
.right
= lpitem
->dxTab
;
2534 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2537 if (lpitem
->fState
& MF_GRAYED
)
2539 if (!(lpitem
->fState
& MF_HILITE
) )
2541 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2542 IntGdiSetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
2543 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2544 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2546 IntGdiSetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
2548 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2553 NtGdiSelectFont (hdc
, hfontOld
);
2558 /***********************************************************************
2561 * Paint a popup menu.
2563 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2565 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2568 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2570 IntGetClientRect( wnd
, &rect
);
2572 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2573 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2574 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2578 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2580 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2583 BOOL flat_menu
= FALSE
;
2585 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2587 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2589 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2591 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2592 /* draw menu items */
2593 if (menu
&& menu
->cItems
)
2598 item
= menu
->rgItems
;
2599 for (u
= 0; u
< menu
->cItems
; u
++, item
++)
2601 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2602 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2604 /* draw scroll arrows */
2605 if (menu
->dwArrowsOn
)
2607 MENU_DrawScrollArrows(menu
, hdc
);
2613 NtGdiSelectBrush( hdc
, hPrevBrush
);
2618 /**********************************************************************
2621 PWND
MENU_IsMenuActive(VOID
)
2623 return ValidateHwndNoErr(top_popup
);
2626 /**********************************************************************
2629 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2631 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2633 void MENU_EndMenu( PWND pwnd
)
2636 menu
= UserGetMenuObject(top_popup_hmenu
);
2637 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2639 if (fInsideMenuLoop
&& top_popup
)
2641 fInsideMenuLoop
= FALSE
;
2645 ERR("Already in End loop\n");
2650 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2656 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2659 HFONT FontOld
= NULL
;
2660 BOOL flat_menu
= FALSE
;
2662 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2666 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2674 if (Rect
== NULL
|| !pMenu
)
2676 return UserGetSystemMetrics(SM_CYMENU
);
2679 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2681 FontOld
= NtGdiSelectFont(hDC
, Font
);
2683 if (pMenu
->cyMenu
== 0)
2685 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2688 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2690 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2692 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2693 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2694 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2695 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2697 if (pMenu
->cItems
== 0)
2699 NtGdiSelectFont(hDC
, FontOld
);
2700 return UserGetSystemMetrics(SM_CYMENU
);
2703 for (i
= 0; i
< pMenu
->cItems
; i
++)
2705 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2708 NtGdiSelectFont(hDC
, FontOld
);
2710 return pMenu
->cyMenu
;
2713 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2716 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2720 // No menu. Do not reserve any space
2726 return UserGetSystemMetrics(SM_CYMENU
);
2731 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2733 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2735 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2737 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2739 return lppop
->cyMenu
;
2743 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2747 /***********************************************************************
2750 * Popup menu initialization before WM_ENTERMENULOOP.
2752 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2755 PPOPUPMENU pPopupMenu
;
2757 LARGE_STRING WindowName
;
2758 UNICODE_STRING ClassName
;
2759 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2761 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2763 menu
->spwndNotify
= pWndOwner
;
2765 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2766 ex_style
= WS_EX_LAYOUTRTL
;
2768 ClassName
.Buffer
= WC_MENU
;
2769 ClassName
.Length
= 0;
2771 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2772 RtlZeroMemory(&Cs
, sizeof(Cs
));
2773 Cs
.style
= WS_POPUP
;
2774 Cs
.dwExStyle
= ex_style
;
2775 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2776 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2777 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2778 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2779 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2781 /* NOTE: In Windows, top menu popup is not owned. */
2782 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2784 if( !pWndCreated
) return FALSE
;
2787 // Setup pop up menu structure.
2789 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2791 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2793 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2794 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2795 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2797 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2798 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2799 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2800 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2801 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2803 if (pPopupMenu
->fRightButton
)
2804 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2806 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2808 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2809 menu
->fFlags
& MNF_RTOL
)
2811 pPopupMenu
->fDroppedLeft
= TRUE
;
2816 /***********************************************************************
2819 * Display a popup menu.
2821 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2822 INT x
, INT y
, INT xanchor
, INT yanchor
)
2828 USER_REFERENCE_ENTRY Ref
;
2830 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2831 pwndOwner
, menu
, id
, x
, y
, xanchor
, yanchor
);
2833 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2835 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2836 menu
->iItem
= NO_SELECTED_ITEM
;
2839 menu
->dwArrowsOn
= 0;
2840 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2842 /* adjust popup menu pos so that it fits within the desktop */
2844 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2845 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2847 /* FIXME: should use item rect */
2850 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2852 if (flags
& TPM_LAYOUTRTL
)
2853 flags
^= TPM_RIGHTALIGN
;
2855 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2856 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2858 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2859 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2861 if( x
+ width
> monitor
->rcMonitor
.right
)
2863 if( xanchor
&& x
>= width
- xanchor
)
2864 x
-= width
- xanchor
;
2866 if( x
+ width
> monitor
->rcMonitor
.right
)
2867 x
= monitor
->rcMonitor
.right
- width
;
2869 if( x
< monitor
->rcMonitor
.left
) x
= monitor
->rcMonitor
.left
;
2871 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2873 if( yanchor
&& y
>= height
+ yanchor
)
2874 y
-= height
+ yanchor
;
2876 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2877 y
= monitor
->rcMonitor
.bottom
- height
;
2879 if( y
< monitor
->rcMonitor
.top
) y
= monitor
->rcMonitor
.top
;
2881 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2885 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2890 top_popup
= menu
->hWnd
;
2891 top_popup_hmenu
= UserHMGetHandle(menu
);
2894 /* Display the window */
2895 UserRefObjectCo(pWnd
, &Ref
);
2896 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2898 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2900 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2901 UserDerefObjectCo(pWnd
);
2906 /***********************************************************************
2907 * MENU_EnsureMenuItemVisible
2909 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2911 USER_REFERENCE_ENTRY Ref
;
2912 if (lppop
->dwArrowsOn
)
2914 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2915 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2916 UINT nOldPos
= lppop
->iTop
;
2918 UINT arrow_bitmap_height
;
2919 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2921 IntGetClientRect(pWnd
, &rc
);
2923 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2925 rc
.top
+= arrow_bitmap_height
;
2926 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2928 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2929 UserRefObjectCo(pWnd
, &Ref
);
2930 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
2932 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
2933 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2934 MENU_DrawScrollArrows(lppop
, hdc
);
2935 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2937 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
2939 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
2940 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2941 MENU_DrawScrollArrows(lppop
, hdc
);
2942 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2944 UserDerefObjectCo(pWnd
);
2948 /***********************************************************************
2951 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
2952 BOOL sendMenuSelect
, PMENU topmenu
)
2955 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
2957 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2959 if (!menu
|| !menu
->cItems
|| !pWnd
) return;
2961 if (menu
->iItem
== wIndex
) return;
2963 if (menu
->fFlags
& MNF_POPUP
)
2964 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
2966 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2969 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
2970 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
2971 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
2974 NtGdiSelectFont( hdc
, ghMenuFont
);
2976 /* Clear previous highlighted item */
2977 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2979 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2980 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
2981 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
2985 /* Highlight new item (if any) */
2986 menu
->iItem
= wIndex
;
2987 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2989 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
2991 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
2992 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
2993 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
2994 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
2998 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
2999 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3000 ip
->fType
| ip
->fState
|
3001 (ip
->spSubMenu
? MF_POPUP
: 0) |
3002 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3004 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3007 else if (sendMenuSelect
)
3012 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3013 if (pos
!= NO_SELECTED_ITEM
)
3015 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3016 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3017 (ip
->spSubMenu
? MF_POPUP
: 0) |
3018 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3020 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3024 UserReleaseDC(pWnd
, hdc
, FALSE
);
3027 /***********************************************************************
3030 * Moves currently selected item according to the Offset parameter.
3031 * If there is no selection then it should select the last item if
3032 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3034 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3038 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3040 if ((!menu
) || (!menu
->rgItems
)) return;
3042 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3044 if ( menu
->cItems
== 1 )
3047 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3049 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3051 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3056 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3057 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3058 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3060 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3065 /***********************************************************************
3068 * Hide the sub-popup menus of this menu.
3070 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3071 BOOL SendMenuSelect
, UINT wFlags
)
3073 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3075 if ( Menu
&& top_popup
)
3079 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3081 Item
= &Menu
->rgItems
[Menu
->iItem
];
3082 if (!(Item
->spSubMenu
) ||
3083 !(Item
->fState
& MF_MOUSESELECT
)) return;
3084 Item
->fState
&= ~MF_MOUSESELECT
;
3089 if (Item
->spSubMenu
)
3092 if (!VerifyMenu(Item
->spSubMenu
)) return;
3093 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3094 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3095 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3096 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3097 co_UserDestroyWindow(pWnd
);
3099 /* Native returns handle to destroyed window */
3100 if (!(wFlags
& TPM_NONOTIFY
))
3102 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3103 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3106 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3107 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3109 Item
->spSubMenu
->hWnd
= NULL
;
3115 /***********************************************************************
3118 * Display the sub-menu of the selected item of this menu.
3119 * Return the handle of the submenu, or menu if no submenu to display.
3121 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3128 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3130 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3132 Item
= &Menu
->rgItems
[Menu
->iItem
];
3133 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3136 /* message must be sent before using item,
3137 because nearly everything may be changed by the application ! */
3139 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3140 if (!(Flags
& TPM_NONOTIFY
))
3142 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3143 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3144 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3147 Item
= &Menu
->rgItems
[Menu
->iItem
];
3148 //Rect = ItemInfo.Rect;
3149 Rect
.left
= Item
->xItem
;
3150 Rect
.top
= Item
->yItem
;
3151 Rect
.right
= Item
->cxItem
; // Do this for now......
3152 Rect
.bottom
= Item
->cyItem
;
3154 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3156 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3157 if (!(Item
->fState
& MF_HILITE
))
3159 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3160 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3162 NtGdiSelectFont(Dc
, ghMenuFont
);
3164 Item
->fState
|= MF_HILITE
;
3165 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3166 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3168 UserReleaseDC(pWnd
, Dc
, FALSE
);
3171 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3173 Item
->xItem
= Rect
.left
;
3174 Item
->yItem
= Rect
.top
;
3175 Item
->cxItem
= Rect
.right
; // Do this for now......
3176 Item
->cyItem
= Rect
.bottom
;
3178 Item
->fState
|= MF_MOUSESELECT
;
3180 if (IS_SYSTEM_MENU(Menu
))
3182 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3184 NC_GetSysPopupPos(pWnd
, &Rect
);
3185 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3186 Rect
.top
= Rect
.bottom
;
3187 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3188 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3192 IntGetWindowRect(pWnd
, &Rect
);
3193 if (Menu
->fFlags
& MNF_POPUP
)
3196 rc
.left
= Item
->xItem
;
3197 rc
.top
= Item
->yItem
;
3198 rc
.right
= Item
->cxItem
; // Do this for now......
3199 rc
.bottom
= Item
->cyItem
;
3201 MENU_AdjustMenuItemRect(Menu
, &rc
);
3203 /* The first item in the popup menu has to be at the
3204 same y position as the focused menu item */
3205 if(Flags
& TPM_LAYOUTRTL
)
3206 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3208 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3209 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3210 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3211 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3212 - UserGetSystemMetrics(SM_CYBORDER
);
3216 if(Flags
& TPM_LAYOUTRTL
)
3217 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3219 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3220 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3221 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3222 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3226 /* use default alignment for submenus */
3227 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3229 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3231 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3232 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3235 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3237 return Item
->spSubMenu
;
3240 /***********************************************************************
3241 * MenuExecFocusedItem
3243 * Execute a menu item (for instance when user pressed Enter).
3244 * Return the wID of the executed item. Otherwise, -1 indicating
3245 * that no menu item was executed, -2 if a popup is shown;
3246 * Have to receive the flags for the TrackPopupMenu options to avoid
3247 * sending unwanted message.
3250 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3254 TRACE("%p menu=%p\n", pmt
, Menu
);
3256 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3261 Item
= &Menu
->rgItems
[Menu
->iItem
];
3263 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3265 if (!(Item
->spSubMenu
))
3267 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3269 /* If TPM_RETURNCMD is set you return the id, but
3270 do not send a message to the owner */
3271 if (!(Flags
& TPM_RETURNCMD
))
3273 if (Menu
->fFlags
& MNF_SYSMENU
)
3275 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3276 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3280 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3282 if (dwStyle
& MNS_NOTIFYBYPOS
)
3283 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3285 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3293 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3300 /***********************************************************************
3301 * MenuSwitchTracking
3303 * Helper function for menu navigation routines.
3305 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3307 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3309 if ( pmt
->TopMenu
!= PtMenu
&&
3310 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3312 /* both are top level menus (system and menu-bar) */
3313 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3314 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3315 pmt
->TopMenu
= PtMenu
;
3319 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3322 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3325 /***********************************************************************
3328 * Return TRUE if we can go on with menu tracking.
3330 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3332 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3338 if (IS_SYSTEM_MENU(PtMenu
))
3340 item
= PtMenu
->rgItems
;
3344 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3349 if (PtMenu
->iItem
!= id
)
3350 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3352 /* If the popup menu is not already "popped" */
3353 if (!(item
->fState
& MF_MOUSESELECT
))
3355 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3360 /* Else the click was on the menu bar, finish the tracking */
3365 /***********************************************************************
3368 * Return the value of MenuExecFocusedItem if
3369 * the selected item was not a popup. Else open the popup.
3370 * A -1 return value indicates that we go on with menu tracking.
3373 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3375 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3382 if ( IS_SYSTEM_MENU(PtMenu
) )
3384 item
= PtMenu
->rgItems
;
3388 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3391 if (item
&& ( PtMenu
->iItem
== Id
))
3393 if (!(item
->spSubMenu
))
3395 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3396 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3397 return ExecutedMenuId
;
3400 /* If we are dealing with the menu bar */
3401 /* and this is a click on an already "popped" item: */
3402 /* Stop the menu tracking and close the opened submenus */
3403 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3408 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3410 PtMenu
->TimeToHide
= TRUE
;
3416 /***********************************************************************
3419 * Walks menu chain trying to find a menu pt maps to.
3421 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3426 if (!menu
) return NULL
;
3428 /* try subpopup first (if any) */
3429 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3431 pItem
= menu
->rgItems
;
3432 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3433 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3435 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3439 /* check the current window (avoiding WM_HITTEST) */
3442 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3443 INT ht
= GetNCHitEx(pWnd
, pt
);
3444 if ( menu
->fFlags
& MNF_POPUP
)
3446 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3448 else if (ht
== HTSYSMENU
)
3449 ret
= get_win_sys_menu(menu
->hWnd
);
3450 else if (ht
== HTMENU
)
3451 ret
= IntGetMenu( menu
->hWnd
);
3456 /***********************************************************************
3459 * Return TRUE if we can go on with menu tracking.
3461 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3463 UINT Index
= NO_SELECTED_ITEM
;
3467 if (IS_SYSTEM_MENU(PtMenu
))
3470 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3473 if (Index
== NO_SELECTED_ITEM
)
3475 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3477 else if (PtMenu
->iItem
!= Index
)
3479 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3480 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3485 /***********************************************************************
3488 * Return the handle of the selected sub-popup menu (if any).
3490 static PMENU
MENU_GetSubPopup( PMENU menu
)
3494 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3496 item
= &menu
->rgItems
[menu
->iItem
];
3497 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3499 return item
->spSubMenu
;
3504 /***********************************************************************
3507 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3509 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3513 /* When skipping left, we need to do something special after the
3515 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3519 /* When skipping right, for the non-system menu, we need to
3520 handle the last non-special menu item (ie skip any window
3521 icons such as MDI maximize, restore or close) */
3522 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3524 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3525 while (i
< pmt
->TopMenu
->cItems
) {
3526 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3527 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3531 if (i
== pmt
->TopMenu
->cItems
) {
3535 /* When skipping right, we need to cater for the system menu */
3536 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3538 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3545 MDINEXTMENU NextMenu
;
3552 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3553 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3554 NextMenu
.hmenuNext
= NULL
;
3555 NextMenu
.hwndNext
= NULL
;
3556 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3558 TRACE("%p [%p] -> %p [%p]\n",
3559 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3561 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3563 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3564 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3566 /* switch to the menu bar */
3568 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3572 Id
= MenuTmp
->cItems
- 1;
3574 /* Skip backwards over any system predefined icons,
3575 eg. MDI close, restore etc icons */
3577 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3578 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3581 hNewMenu
= UserHMGetHandle(MenuTmp
);
3583 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3585 /* switch to the system menu */
3586 MenuTmp
= get_win_sys_menu(hNewWnd
);
3587 hNewMenu
= UserHMGetHandle(MenuTmp
);
3592 else /* application returned a new menu to switch to */
3594 hNewMenu
= NextMenu
.hmenuNext
;
3595 hNewWnd
= NextMenu
.hwndNext
;
3597 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3599 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3601 /* get the real system menu */
3602 MenuTmp
= get_win_sys_menu(hNewWnd
);
3603 hNewMenu
= UserHMGetHandle(MenuTmp
);
3605 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3607 /* FIXME: Not sure what to do here;
3608 * perhaps try to track NewMenu as a popup? */
3610 WARN(" -- got confused.\n");
3617 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3619 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3621 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3622 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3625 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3627 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3628 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3629 ///// Use thread pms!!!!
3630 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3631 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3632 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3633 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3636 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3637 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3644 /***********************************************************************
3647 * The idea is not to show the popup if the next input message is
3648 * going to hide it anyway.
3650 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3654 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3656 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3657 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3662 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3663 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3665 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3666 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3667 if( msg
.message
== WM_KEYDOWN
&&
3668 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3670 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3676 /* failures go through this */
3677 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3681 /***********************************************************************
3684 * Handle a VK_ESCAPE key event in a menu.
3686 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3688 BOOL EndMenu
= TRUE
;
3690 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3692 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3694 PMENU MenuPrev
, MenuTmp
;
3696 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3698 /* close topmost popup */
3699 while (MenuTmp
!= pmt
->CurrentMenu
)
3702 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3705 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3706 pmt
->CurrentMenu
= MenuPrev
;
3714 /***********************************************************************
3717 * Handle a VK_LEFT key event in a menu.
3719 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
)
3721 PMENU MenuTmp
, MenuPrev
;
3724 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3726 /* Try to move 1 column left (if possible) */
3727 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3729 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3733 /* close topmost popup */
3734 while (MenuTmp
!= pmt
->CurrentMenu
)
3737 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3740 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3741 pmt
->CurrentMenu
= MenuPrev
;
3743 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3745 /* move menu bar selection if no more popups are left */
3747 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3748 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3750 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3752 /* A sublevel menu was displayed - display the next one
3753 * unless there is another displacement coming up */
3755 if (!MENU_SuspendPopup(pmt
, WM_KEYDOWN
))
3756 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3762 /***********************************************************************
3765 * Handle a VK_RIGHT key event in a menu.
3767 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
)
3772 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3773 pmt
->CurrentMenu
, pmt
->TopMenu
);
3775 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3777 /* If already displaying a popup, try to display sub-popup */
3779 menutmp
= pmt
->CurrentMenu
;
3780 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3782 /* if subpopup was displayed then we are done */
3783 if (menutmp
!= pmt
->CurrentMenu
) return;
3786 /* Check to see if there's another column */
3787 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3789 TRACE("Going to %d.\n", NextCol
);
3790 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3794 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3796 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3798 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3799 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3806 /* try to move to the next item */
3807 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3808 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3810 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3812 if ( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
3813 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3818 /***********************************************************************
3821 * Menu tracking code.
3823 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3824 PWND pwnd
, const RECT
*lprect
)
3828 INT executedMenuId
= -1;
3832 BOOL enterIdleSent
= FALSE
;
3833 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3835 if (pti
!= pwnd
->head
.pti
)
3837 ERR("Not the same PTI!!!!\n");
3841 mt
.CurrentMenu
= pmenu
;
3847 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3848 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3849 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3851 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3853 if (wFlags
& TPM_BUTTONDOWN
)
3855 /* Get the result in order to start the tracking or not */
3856 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3857 fInsideMenuLoop
= fRemove
;
3860 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3862 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3864 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3865 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3866 co_UserSetCapture(NULL
); /* release the capture */
3870 capture_win
= IntGetCapture();
3872 while (fInsideMenuLoop
)
3874 BOOL ErrorExit
= FALSE
;
3875 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3878 /* we have to keep the message in the queue until it's
3879 * clear that menu loop is not over yet. */
3883 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3885 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3886 /* remove the message from the queue */
3887 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3891 /* ReactOS Checks */
3892 if (!VerifyWnd(mt
.OwnerWnd
) ||
3893 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3894 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3895 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3897 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3903 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3904 enterIdleSent
= TRUE
;
3905 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3907 co_IntWaitMessage(NULL
, 0, 0);
3911 if (ErrorExit
) break; // Gracefully dropout.
3913 /* check if EndMenu() tried to cancel us, by posting this message */
3914 if (msg
.message
== WM_CANCELMODE
)
3916 /* we are now out of the loop */
3917 fInsideMenuLoop
= FALSE
;
3919 /* remove the message from the queue */
3920 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3922 /* break out of internal loop, ala ESCAPE */
3926 IntTranslateKbdMessage(&msg
, 0);
3929 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3930 enterIdleSent
=FALSE
;
3933 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3936 * Use the mouse coordinates in lParam instead of those in the MSG
3937 * struct to properly handle synthetic messages. They are already
3938 * in screen coordinates.
3940 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3941 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3943 /* Find a menu for this mouse event */
3944 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3948 /* no WM_NC... messages in captured state */
3950 case WM_RBUTTONDBLCLK
:
3951 case WM_RBUTTONDOWN
:
3952 if (!(wFlags
& TPM_RIGHTBUTTON
))
3954 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3958 case WM_LBUTTONDBLCLK
:
3959 case WM_LBUTTONDOWN
:
3960 /* If the message belongs to the menu, removes it from the queue */
3961 /* Else, end menu tracking */
3962 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3963 fInsideMenuLoop
= fRemove
;
3964 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3965 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3969 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3972 /* Check if a menu was selected by the mouse */
3975 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
3977 /* End the loop if executedMenuId is an item ID */
3978 /* or if the job was done (executedMenuId = 0). */
3979 fRemove
= (executedMenuId
!= -1);
3980 fInsideMenuLoop
= !fRemove
;
3982 /* No menu was selected by the mouse */
3983 /* if the function was called by TrackPopupMenu, continue
3984 with the menu tracking. If not, stop it */
3986 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
3991 /* the selected menu item must be changed every time */
3992 /* the mouse moves. */
3995 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
3997 } /* switch(msg.message) - mouse */
3999 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4001 fRemove
= TRUE
; /* Keyboard messages are always removed */
4010 fInsideMenuLoop
= FALSE
;
4015 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4016 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4020 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4021 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4022 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4023 else /* otherwise try to move selection */
4024 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4028 MENU_KeyLeft( &mt
, wFlags
);
4032 MENU_KeyRight( &mt
, wFlags
);
4036 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4042 hi
.cbSize
= sizeof(HELPINFO
);
4043 hi
.iContextType
= HELPINFO_MENUITEM
;
4044 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4047 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4048 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4049 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4050 hi
.MousePos
= msg
.pt
;
4051 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4058 break; /* WM_KEYDOWN */
4066 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4068 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4069 fEndMenu
= (executedMenuId
!= -2);
4070 fInsideMenuLoop
= !fEndMenu
;
4074 /* Hack to avoid control chars. */
4075 /* We will find a better way real soon... */
4076 if (msg
.wParam
< 32) break;
4078 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4080 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4081 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4084 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4085 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4086 fEndMenu
= (executedMenuId
!= -2);
4087 fInsideMenuLoop
= !fEndMenu
;
4091 } /* switch(msg.message) - kbd */
4095 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4096 IntDispatchMessage( &msg
);
4100 if (fInsideMenuLoop
) fRemove
= TRUE
;
4102 /* finally remove message from the queue */
4104 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4105 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4106 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4109 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4110 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4111 co_UserSetCapture(NULL
); /* release the capture */
4113 /* If dropdown is still painted and the close box is clicked on
4114 then the menu will be destroyed as part of the DispatchMessage above.
4115 This will then invalidate the menu handle in mt.hTopMenu. We should
4116 check for this first. */
4117 if ( VerifyMenu( mt
.TopMenu
) )
4119 if (VerifyWnd(mt
.OwnerWnd
))
4121 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4123 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4125 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4126 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4128 co_UserDestroyWindow(pwndTM
);
4129 mt
.TopMenu
->hWnd
= NULL
;
4131 if (!(wFlags
& TPM_NONOTIFY
))
4133 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4134 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4137 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4138 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4141 /* Reset the variable for hiding menu */
4142 mt
.TopMenu
->TimeToHide
= FALSE
;
4145 /* The return value is only used by TrackPopupMenu */
4146 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4147 if (executedMenuId
== -1) executedMenuId
= 0;
4148 return executedMenuId
;
4151 /***********************************************************************
4154 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4157 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4159 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4161 co_UserHideCaret(0);
4163 /* This makes the menus of applications built with Delphi work.
4164 * It also enables menus to be displayed in more than one window,
4165 * but there are some bugs left that need to be fixed in this case.
4169 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4173 top_popup
= Menu
->hWnd
;
4174 top_popup_hmenu
= UserHMGetHandle(Menu
);
4177 fInsideMenuLoop
= TRUE
;
4180 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4181 if (!(wFlags
& TPM_NONOTIFY
))
4183 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4187 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4189 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4190 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4191 co_UserSetCapture(capture_win
); // 2
4192 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4194 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4196 if (!(wFlags
& TPM_NONOTIFY
))
4198 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4199 /* If an app changed/recreated menu bar entries in WM_INITMENU
4200 * menu sizes will be recalculated once the menu created/shown.
4204 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4206 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4211 /***********************************************************************
4214 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4216 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4218 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4220 if (!(wFlags
& TPM_NONOTIFY
))
4221 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4223 co_UserShowCaret(0);
4226 top_popup_hmenu
= NULL
;
4231 /***********************************************************************
4232 * MenuTrackMouseMenuBar
4234 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4236 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4238 PMENU pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4239 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4241 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4243 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4244 if (VerifyMenu(pMenu
))
4246 /* map point to parent client coordinates */
4247 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4248 if (Parent
!= UserGetDesktopWindow())
4250 IntScreenToClient(Parent
, &pt
);
4253 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4254 /* fetch the window menu again, it may have changed */
4255 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4256 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4257 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4261 /***********************************************************************
4262 * MenuTrackKbdMenuBar
4264 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4266 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4268 UINT uItem
= NO_SELECTED_ITEM
;
4270 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4272 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4274 /* find window that has a menu */
4276 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4277 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4279 /* check if we have to track a system menu */
4281 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4282 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4284 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4285 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4287 wParam
|= HTSYSMENU
; /* prevent item lookup */
4290 if (!VerifyMenu( TrackMenu
)) return;
4292 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4294 /* fetch the window menu again, it may have changed */
4295 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4297 if( wChar
&& wChar
!= ' ' )
4299 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4300 if ( uItem
>= (UINT
)(-2) )
4302 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4303 /* schedule end of menu tracking */
4304 wFlags
|= TF_ENDMENU
;
4309 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4311 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4313 if( uItem
== NO_SELECTED_ITEM
)
4314 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4316 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4320 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4321 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4324 /**********************************************************************
4325 * TrackPopupMenuEx (USER32.@)
4327 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4328 PWND pWnd
, LPTPMPARAMS lpTpm
)
4331 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4333 if (pti
!= pWnd
->head
.pti
)
4335 ERR("Must be the same pti!\n");
4339 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4340 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4341 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4343 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4345 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4349 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4351 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4353 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4354 if (!(wFlags
& TPM_NONOTIFY
))
4356 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4359 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4360 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4361 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4364 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4365 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4366 co_UserSetCapture(NULL
); /* release the capture */
4370 // HACK : Until back trace fault in co_IntUpdateWindows and MENU_TrackMenu.
4372 if (EngGetLastError() == ERROR_ACCESS_DENIED
)
4374 EngSetLastError(NO_ERROR
);
4377 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4381 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4382 if (pwndM
) // wine hack around this with their destroy function.
4383 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4386 if (!(wFlags
& TPM_NONOTIFY
))
4388 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4389 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4407 PPOPUPMENU pPopupMenu
;
4411 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4417 if (Message
!= WM_NCCREATE
)
4419 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4422 Wnd
->fnid
= FNID_MENU
;
4423 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4424 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4425 pPopupMenu
->spwndPopupMenu
= Wnd
;
4426 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4427 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4433 if (Wnd
->fnid
!= FNID_MENU
)
4435 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4438 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4446 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4447 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4451 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4452 *lResult
= MA_NOACTIVATE
;
4458 IntBeginPaint(Wnd
, &ps
);
4459 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4460 IntEndPaint(Wnd
, &ps
);
4464 case WM_PRINTCLIENT
:
4466 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4475 /* zero out global pointer in case resident popup window was destroyed. */
4478 if (UserHMGetHandle(Wnd
) == top_popup
)
4481 top_popup_hmenu
= NULL
;
4486 ERR("No Window Pop Up!\n");
4492 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4493 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4494 Wnd
->fnid
= FNID_DESTROY
;
4498 case MM_SETMENUHANDLE
: // wine'isms
4501 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4504 ERR("Bad Menu Handle\n");
4507 pPopupMenu
->spmenu
= pmenu
;
4511 case MM_GETMENUHANDLE
: // wine'isms
4513 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4517 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4519 ERR("Someone is passing unknown menu messages %d\n",Message
);
4521 TRACE("PMWP to IDWP %d\n",Message
);
4522 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4530 IntHiliteMenuItem(PWND WindowObject
,
4536 UINT uItem
= uItemHilite
;
4538 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4540 if (uHilite
& MF_HILITE
)
4542 MenuItem
->fState
|= MF_HILITE
;
4546 MenuItem
->fState
&= ~MF_HILITE
;
4548 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4549 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4550 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4552 return TRUE
; // Always returns true!!!!
4556 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4560 DWORD dwExStyle
= 0;
4561 BOOLEAN retValue
= TRUE
;
4563 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4565 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4567 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4569 dwStyle
= pWindowObject
->style
;
4570 dwExStyle
= pWindowObject
->ExStyle
;
4572 bti
->rcTitleBar
.top
= 0;
4573 bti
->rcTitleBar
.left
= 0;
4574 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4575 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4577 /* Is it iconiced ? */
4578 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4580 /* Remove frame from rectangle */
4581 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4583 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4584 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4586 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4588 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4589 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4591 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4593 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4594 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4597 /* We have additional border information if the window
4598 * is a child (but not an MDI child) */
4599 if ( (dwStyle
& WS_CHILD
) &&
4600 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4602 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4604 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4605 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4608 if (dwExStyle
& WS_EX_STATICEDGE
)
4610 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4611 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4616 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4617 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4618 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4620 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4621 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4623 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4624 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4628 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4629 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4630 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4633 if (dwStyle
& WS_CAPTION
)
4635 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4636 if (dwStyle
& WS_SYSMENU
)
4638 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4640 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4641 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4645 if (!(dwStyle
& WS_MINIMIZEBOX
))
4647 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4649 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4651 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4655 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4657 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4659 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4661 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4666 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4667 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4668 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4669 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4674 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4679 EngSetLastError(ERROR_INVALID_PARAMETER
);
4691 LPCMENUITEMINFOW UnsafeItemInfo
,
4692 PUNICODE_STRING lpstr
)
4695 ROSMENUITEMINFO ItemInfo
;
4697 /* Try to copy the whole MENUITEMINFOW structure */
4698 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4699 if (NT_SUCCESS(Status
))
4701 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4702 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4704 EngSetLastError(ERROR_INVALID_PARAMETER
);
4707 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4710 /* Try to copy without last field (not present in older versions) */
4711 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4712 if (NT_SUCCESS(Status
))
4714 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4716 EngSetLastError(ERROR_INVALID_PARAMETER
);
4719 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4720 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4723 SetLastNtError(Status
);
4727 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4732 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4737 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4739 if (pItem
->spSubMenu
)
4741 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
) & 0xff);
4744 return (pItem
->fType
| pItem
->fState
);
4747 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4752 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4757 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4759 if (pItem
->spSubMenu
)
4761 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4767 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4769 PMENU menu
, pSubTarget
;
4771 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4772 return NO_SELECTED_ITEM
;
4774 pSubTarget
= UserGetMenuObject(hSubTarget
);
4776 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4778 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4784 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4786 PWINSTATION_OBJECT WinStaObject
;
4790 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4792 if (gpepCSRSS
!= CurrentProcess
)
4795 * gpepCSRSS does not have a Win32WindowStation
4798 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4804 if (!NT_SUCCESS(Status
))
4806 ERR("Validation of window station handle (%p) failed\n",
4807 CurrentProcess
->Win32WindowStation
);
4808 SetLastNtError(Status
);
4811 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4812 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4814 ERR("Desktop Window Station does not match Process one!\n");
4816 ObDereferenceObject(WinStaObject
);
4820 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4823 if (Menu
) UserDereferenceObject(Menu
);
4824 return (HMENU
)Handle
;
4832 PROSMENUITEMINFO ItemInfo
,
4834 PUNICODE_STRING lpstr
)
4839 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4841 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4846 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4850 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4860 PROSMENUITEMINFO UnsafeItemInfo
,
4862 PUNICODE_STRING lpstr
)
4865 ROSMENUITEMINFO ItemInfo
;
4870 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4871 if (! NT_SUCCESS(Status
))
4873 SetLastNtError(Status
);
4876 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4877 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4878 Size
!= sizeof(ROSMENUITEMINFO
) )
4880 EngSetLastError(ERROR_INVALID_PARAMETER
);
4883 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4884 if (! NT_SUCCESS(Status
))
4886 SetLastNtError(Status
);
4889 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4891 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4892 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4894 EngSetLastError(ERROR_INVALID_PARAMETER
);
4898 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4900 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4901 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4904 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4910 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4914 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4917 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4918 if (! NT_SUCCESS(Status
))
4920 SetLastNtError(Status
);
4932 PROSMENUINFO UnsafeMenuInfo
,
4938 ROSMENUINFO MenuInfo
;
4940 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4941 if (! NT_SUCCESS(Status
))
4943 SetLastNtError(Status
);
4946 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4948 EngSetLastError(ERROR_INVALID_PARAMETER
);
4951 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4952 if (! NT_SUCCESS(Status
))
4954 SetLastNtError(Status
);
4961 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4966 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4969 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
4970 if (! NT_SUCCESS(Status
))
4972 SetLastNtError(Status
);
4992 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
4994 Rect
->left
= MenuItem
->xItem
;
4995 Rect
->top
= MenuItem
->yItem
;
4996 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
4997 Rect
->bottom
= MenuItem
->cyItem
;
5001 ERR("Failed Item Lookup! %u\n", uItem
);
5007 HWND hWnd
= Menu
->hWnd
;
5008 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5011 if (Menu
->fFlags
& MNF_POPUP
)
5013 XMove
= pWnd
->rcClient
.left
;
5014 YMove
= pWnd
->rcClient
.top
;
5018 XMove
= pWnd
->rcWindow
.left
;
5019 YMove
= pWnd
->rcWindow
.top
;
5022 Rect
->left
+= XMove
;
5024 Rect
->right
+= XMove
;
5025 Rect
->bottom
+= YMove
;
5030 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5032 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5033 HMENU hSysMenu
, hNewMenu
= NULL
;
5034 ROSMENUITEMINFO ItemInfoSet
= {0};
5035 ROSMENUITEMINFO ItemInfo
= {0};
5036 UNICODE_STRING MenuName
;
5038 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5039 if (NULL
== hSysMenu
)
5043 SysMenu
= UserGetMenuObject(hSysMenu
);
5044 if (NULL
== SysMenu
)
5046 UserDestroyMenu(hSysMenu
);
5050 SysMenu
->fFlags
|= MNF_SYSMENU
;
5051 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5055 //hNewMenu = co_IntLoadSysMenuTemplate();
5056 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5058 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5059 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5063 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5064 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5065 //ERR("%wZ\n",&MenuName);
5070 IntReleaseMenuObject(SysMenu
);
5071 UserDestroyMenu(hSysMenu
);
5074 Menu
= UserGetMenuObject(hNewMenu
);
5077 IntReleaseMenuObject(SysMenu
);
5078 UserDestroyMenu(hSysMenu
);
5082 // Do the rest in here.
5084 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5086 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5087 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5088 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5089 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5090 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5091 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5092 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5093 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5094 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5095 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5097 NewMenu
= IntCloneMenu(Menu
);
5099 IntReleaseMenuObject(NewMenu
);
5100 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5102 IntDestroyMenuObject(Menu
, FALSE
);
5110 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5112 if (Window
->pcls
->style
& CS_NOCLOSE
)
5113 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5115 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5116 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5118 ItemInfo
.fState
= MFS_ENABLED
;
5119 ItemInfo
.dwTypeData
= NULL
;
5121 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5122 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5126 ERR("failed to load system menu!\n");
5131 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5137 if (Window
->SystemMenu
)
5139 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5140 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5142 IntDestroyMenuObject(Menu
, TRUE
);
5143 Window
->SystemMenu
= NULL
;
5149 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5150 if ((!Window
->SystemMenu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5152 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5153 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5157 if (Window
->SystemMenu
)
5159 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5160 /* Store the dummy sysmenu handle to facilitate the refresh */
5161 /* of the close button if the SC_CLOSE item change */
5162 Menu
= UserGetMenuObject(hMenu
);
5165 Menu
->spwndNotify
= Window
;
5166 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5174 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5178 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5180 if (Window
->SystemMenu
)
5182 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5185 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5186 IntDestroyMenuObject(OldMenu
, TRUE
);
5190 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5192 { // Use spmenuSys too!
5193 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5196 Window
->SystemMenu
= NULL
;
5198 if (Menu
&& Window
!= Menu
->spwndNotify
)
5200 Menu
->spwndNotify
= Window
;
5212 PMENU OldMenu
, NewMenu
= NULL
;
5214 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5216 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5217 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5221 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5229 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5230 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5239 NewMenu
= IntGetMenuObject(Menu
);
5240 if (NULL
== NewMenu
)
5242 if (NULL
!= OldMenu
)
5244 IntReleaseMenuObject(OldMenu
);
5246 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5249 if (NULL
!= NewMenu
->hWnd
)
5251 /* Can't use the same menu for two windows */
5252 if (NULL
!= OldMenu
)
5254 IntReleaseMenuObject(OldMenu
);
5256 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5262 Wnd
->IDMenu
= (UINT
) Menu
;
5263 if (NULL
!= NewMenu
)
5265 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5266 IntReleaseMenuObject(NewMenu
);
5268 if (NULL
!= OldMenu
)
5270 OldMenu
->hWnd
= NULL
;
5271 IntReleaseMenuObject(OldMenu
);
5278 /* FUNCTIONS *****************************************************************/
5284 NtUserCheckMenuItem(
5290 DECLARE_RETURN(DWORD
);
5292 TRACE("Enter NtUserCheckMenuItem\n");
5293 UserEnterExclusive();
5295 if(!(Menu
= UserGetMenuObject(hMenu
)))
5300 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5303 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5318 DECLARE_RETURN(BOOL
);
5320 TRACE("Enter NtUserDeleteMenu\n");
5321 UserEnterExclusive();
5323 if(!(Menu
= UserGetMenuObject(hMenu
)))
5328 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5331 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5337 * NtUserGetSystemMenu
5339 * The NtUserGetSystemMenu function allows the application to access the
5340 * window menu (also known as the system menu or the control menu) for
5341 * copying and modifying.
5345 * Handle to the window that will own a copy of the window menu.
5347 * Specifies the action to be taken. If this parameter is FALSE,
5348 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5349 * currently in use. The copy is initially identical to the window menu
5350 * but it can be modified.
5351 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5352 * to the default state. The previous window menu, if any, is destroyed.
5355 * If the bRevert parameter is FALSE, the return value is a handle to a
5356 * copy of the window menu. If the bRevert parameter is TRUE, the return
5364 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5368 DECLARE_RETURN(HMENU
);
5370 TRACE("Enter NtUserGetSystemMenu\n");
5373 if (!(Window
= UserGetWindowObject(hWnd
)))
5378 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5383 RETURN(Menu
->head
.h
);
5386 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5392 * NtUserSetSystemMenu
5399 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5401 BOOL Result
= FALSE
;
5404 DECLARE_RETURN(BOOL
);
5406 TRACE("Enter NtUserSetSystemMenu\n");
5407 UserEnterExclusive();
5409 if (!(Window
= UserGetWindowObject(hWnd
)))
5417 * Assign new menu handle and Up the Lock Count.
5419 if (!(Menu
= IntGetMenuObject(hMenu
)))
5424 Result
= IntSetSystemMenu(Window
, Menu
);
5427 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5432 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5441 NtUserGetTitleBarInfo(
5446 TITLEBARINFO bartitleinfo
;
5447 DECLARE_RETURN(BOOLEAN
);
5448 BOOLEAN retValue
= TRUE
;
5450 TRACE("Enter NtUserGetTitleBarInfo\n");
5451 UserEnterExclusive();
5453 /* Vaildate the windows handle */
5454 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5456 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5462 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5463 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5464 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5466 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5468 /* Fail copy the data */
5469 EngSetLastError(ERROR_INVALID_PARAMETER
);
5474 /* Get the tile bar info */
5477 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5482 /* Copy our buffer to user mode buffer bti */
5483 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5484 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5486 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5488 /* Fail copy the data */
5489 EngSetLastError(ERROR_INVALID_PARAMETER
);
5499 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5507 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5510 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5512 if(!(Menu
= UserGetMenuObject(hMenu
)))
5517 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5519 EngSetLastError(ERROR_ACCESS_DENIED
);
5522 return IntDestroyMenuObject(Menu
, FALSE
);
5533 DECLARE_RETURN(BOOL
);
5535 TRACE("Enter NtUserDestroyMenu\n");
5536 UserEnterExclusive();
5538 if(!(Menu
= UserGetMenuObject(hMenu
)))
5542 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5544 EngSetLastError(ERROR_ACCESS_DENIED
);
5547 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5550 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5559 NtUserEnableMenuItem(
5565 DECLARE_RETURN(UINT
);
5567 TRACE("Enter NtUserEnableMenuItem\n");
5568 UserEnterExclusive();
5570 if(!(Menu
= UserGetMenuObject(hMenu
)))
5575 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5578 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5590 TRACE("Enter NtUserEndMenu\n");
5591 UserEnterExclusive();
5592 /* if ( gptiCurrent->pMenuState &&
5593 gptiCurrent->pMenuState->pGlobalPopupMenu )
5595 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5598 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5601 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5603 if (fInsideMenuLoop
&& top_popup
)
5605 fInsideMenuLoop
= FALSE
;
5606 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5609 TRACE("Leave NtUserEndMenu\n");
5617 NtUserGetMenuBarInfo(
5627 PPOPUPMENU pPopupMenu
;
5628 USER_REFERENCE_ENTRY Ref
;
5629 NTSTATUS Status
= STATUS_SUCCESS
;
5631 DECLARE_RETURN(BOOL
);
5633 TRACE("Enter NtUserGetMenuBarInfo\n");
5636 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5638 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5642 UserRefObjectCo(pWnd
, &Ref
);
5644 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5646 kmbi
.hwndMenu
= NULL
;
5647 kmbi
.fBarFocused
= FALSE
;
5648 kmbi
.fFocused
= FALSE
;
5653 if (!pWnd
->pcls
->fnid
)
5655 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5657 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5658 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5661 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5662 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5663 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5664 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5666 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5668 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5673 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5674 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5675 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5678 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5679 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5680 hMenu
= UserHMGetHandle(Menu
);
5691 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5692 kmbi
.cbSize
= pmbi
->cbSize
;
5694 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5700 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5702 EngSetLastError(ERROR_INVALID_PARAMETER
);
5706 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5710 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5715 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5716 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5717 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5718 TRACE("idItem a 0 %d\n",Ret
);
5722 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5723 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5727 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5728 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5731 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5732 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5734 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5739 kmbi
.fFocused
= kmbi
.fBarFocused
;
5744 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5745 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5747 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5749 Status
= _SEH2_GetExceptionCode();
5753 if (!NT_SUCCESS(Status
))
5755 SetLastNtError(Status
);
5762 if (pWnd
) UserDerefObjectCo(pWnd
);
5763 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5776 PMENU Menu
, SubMenu
;
5779 DECLARE_RETURN(UINT
);
5781 TRACE("Enter NtUserGetMenuIndex\n");
5784 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5785 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5788 MenuItem
= Menu
->rgItems
;
5789 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5791 if (MenuItem
->spSubMenu
== SubMenu
)
5792 RETURN(MenuItem
->wID
);
5797 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5806 NtUserGetMenuItemRect(
5817 NTSTATUS Status
= STATUS_SUCCESS
;
5818 DECLARE_RETURN(BOOL
);
5820 TRACE("Enter NtUserGetMenuItemRect\n");
5823 if (!(Menu
= UserGetMenuObject(hMenu
)))
5828 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5830 Rect
.left
= MenuItem
->xItem
;
5831 Rect
.top
= MenuItem
->yItem
;
5832 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5833 Rect
.bottom
= MenuItem
->cyItem
;
5843 if (lprcItem
== NULL
) RETURN( FALSE
);
5845 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5847 if (Menu
->fFlags
& MNF_POPUP
)
5849 XMove
= ReferenceWnd
->rcClient
.left
;
5850 YMove
= ReferenceWnd
->rcClient
.top
;
5854 XMove
= ReferenceWnd
->rcWindow
.left
;
5855 YMove
= ReferenceWnd
->rcWindow
.top
;
5860 Rect
.right
+= XMove
;
5861 Rect
.bottom
+= YMove
;
5865 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5867 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5869 Status
= _SEH2_GetExceptionCode();
5873 if (!NT_SUCCESS(Status
))
5875 SetLastNtError(Status
);
5881 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5890 NtUserHiliteMenuItem(
5898 DECLARE_RETURN(BOOLEAN
);
5900 TRACE("Enter NtUserHiliteMenuItem\n");
5901 UserEnterExclusive();
5903 if(!(Window
= UserGetWindowObject(hWnd
)))
5905 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5909 if(!(Menu
= UserGetMenuObject(hMenu
)))
5911 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5915 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
5918 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
5928 NtUserDrawMenuBarTemp(
5938 NTSTATUS Status
= STATUS_SUCCESS
;
5939 DECLARE_RETURN(DWORD
);
5941 ERR("Enter NtUserDrawMenuBarTemp\n");
5942 UserEnterExclusive();
5944 if(!(Window
= UserGetWindowObject(hWnd
)))
5946 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5950 if(!(Menu
= UserGetMenuObject(hMenu
)))
5952 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5958 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
5959 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
5961 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5963 Status
= _SEH2_GetExceptionCode();
5967 if (Status
!= STATUS_SUCCESS
)
5969 SetLastNtError(Status
);
5973 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
5976 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
5985 NtUserMenuItemFromPoint(
5995 DECLARE_RETURN(int);
5997 TRACE("Enter NtUserMenuItemFromPoint\n");
5998 UserEnterExclusive();
6000 if (!(Menu
= UserGetMenuObject(hMenu
)))
6005 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6010 X
-= Window
->rcWindow
.left
;
6011 Y
-= Window
->rcWindow
.top
;
6014 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6018 Rect
.left
= mi
->xItem
;
6019 Rect
.top
= mi
->yItem
;
6020 Rect
.right
= mi
->cxItem
;
6021 Rect
.bottom
= mi
->cyItem
;
6023 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6025 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6031 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6034 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6050 DECLARE_RETURN(BOOL
);
6052 TRACE("Enter NtUserRemoveMenu\n");
6053 UserEnterExclusive();
6055 if(!(Menu
= UserGetMenuObject(hMenu
)))
6060 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6063 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6080 DECLARE_RETURN(BOOL
);
6082 TRACE("Enter NtUserSetMenu\n");
6083 UserEnterExclusive();
6085 if (!(Window
= UserGetWindowObject(hWnd
)))
6090 if (!IntSetMenu(Window
, Menu
, &Changed
))
6095 // Not minimized and please repaint!!!
6096 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6098 USER_REFERENCE_ENTRY Ref
;
6099 UserRefObjectCo(Window
, &Ref
);
6100 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6101 UserDerefObjectCo(Window
);
6107 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6116 NtUserSetMenuContextHelpId(
6118 DWORD dwContextHelpId
)
6121 DECLARE_RETURN(BOOL
);
6123 TRACE("Enter NtUserSetMenuContextHelpId\n");
6124 UserEnterExclusive();
6126 if(!(Menu
= UserGetMenuObject(hMenu
)))
6131 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6134 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6143 NtUserSetMenuDefaultItem(
6149 DECLARE_RETURN(BOOL
);
6151 TRACE("Enter NtUserSetMenuDefaultItem\n");
6152 UserEnterExclusive();
6154 if(!(Menu
= UserGetMenuObject(hMenu
)))
6159 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6162 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6171 NtUserSetMenuFlagRtoL(
6175 DECLARE_RETURN(BOOL
);
6177 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6178 UserEnterExclusive();
6180 if(!(Menu
= UserGetMenuObject(hMenu
)))
6185 RETURN(IntSetMenuFlagRtoL(Menu
));
6188 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6197 NtUserThunkedMenuInfo(
6202 DECLARE_RETURN(BOOL
);
6204 TRACE("Enter NtUserThunkedMenuInfo\n");
6205 UserEnterExclusive();
6207 if (!(Menu
= UserGetMenuObject(hMenu
)))
6212 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6215 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6224 NtUserThunkedMenuItemInfo(
6229 LPMENUITEMINFOW lpmii
,
6230 PUNICODE_STRING lpszCaption
)
6234 UNICODE_STRING lstrCaption
;
6235 DECLARE_RETURN(BOOL
);
6237 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6238 UserEnterExclusive();
6240 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6241 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6243 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6245 if (!(Menu
= UserGetMenuObject(hMenu
)))
6250 /* Check if we got a Caption */
6251 if (lpszCaption
&& lpszCaption
->Buffer
)
6253 /* Copy the string to kernel mode */
6254 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6257 if (!NT_SUCCESS(Status
))
6259 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6260 SetLastNtError(Status
);
6265 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6267 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6270 if (lstrCaption
.Buffer
)
6272 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6275 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6284 NtUserTrackPopupMenuEx(
6296 USER_REFERENCE_ENTRY Ref
;
6298 TRACE("Enter NtUserTrackPopupMenuEx\n");
6299 UserEnterExclusive();
6300 /* Parameter check */
6301 if (!(menu
= UserGetMenuObject( hMenu
)))
6303 ERR("TPME : Invalid Menu handle.\n");
6304 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6308 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6310 ERR("TPME : Invalid Window handle.\n");
6318 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6323 _SEH2_YIELD(goto Exit
);
6327 UserRefObjectCo(pWnd
, &Ref
);
6328 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6329 UserDerefObjectCo(pWnd
);
6332 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);