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 ( (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
= menu
->cItems
; u
> 0; 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
)
2957 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2959 if (!menu
|| !menu
->cItems
) return;
2961 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
2965 if (menu
->iItem
== wIndex
) return;
2967 if (menu
->fFlags
& MNF_POPUP
)
2968 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
2970 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2973 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
2974 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
2975 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
2978 NtGdiSelectFont( hdc
, ghMenuFont
);
2980 /* Clear previous highlighted item */
2981 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2983 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2984 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
2985 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
2989 /* Highlight new item (if any) */
2990 menu
->iItem
= wIndex
;
2991 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2993 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
2995 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
2996 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
2997 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
2998 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3002 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3003 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3004 ip
->fType
| ip
->fState
|
3005 (ip
->spSubMenu
? MF_POPUP
: 0) |
3006 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3008 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3011 else if (sendMenuSelect
)
3016 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3017 if (pos
!= NO_SELECTED_ITEM
)
3019 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3020 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3021 (ip
->spSubMenu
? MF_POPUP
: 0) |
3022 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3024 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3028 UserReleaseDC(pWnd
, hdc
, FALSE
);
3031 /***********************************************************************
3034 * Moves currently selected item according to the Offset parameter.
3035 * If there is no selection then it should select the last item if
3036 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3038 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3042 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3044 if ((!menu
) || (!menu
->rgItems
)) return;
3046 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3048 if ( menu
->cItems
== 1 )
3051 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3053 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3055 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3060 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3061 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3062 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3064 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3069 /***********************************************************************
3072 * Hide the sub-popup menus of this menu.
3074 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3075 BOOL SendMenuSelect
, UINT wFlags
)
3077 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3079 if ( Menu
&& top_popup
)
3083 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3085 Item
= &Menu
->rgItems
[Menu
->iItem
];
3086 if (!(Item
->spSubMenu
) ||
3087 !(Item
->fState
& MF_MOUSESELECT
)) return;
3088 Item
->fState
&= ~MF_MOUSESELECT
;
3093 if (Item
->spSubMenu
)
3096 if (!VerifyMenu(Item
->spSubMenu
)) return;
3097 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3098 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3099 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3100 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3101 co_UserDestroyWindow(pWnd
);
3103 /* Native returns handle to destroyed window */
3104 if (!(wFlags
& TPM_NONOTIFY
))
3106 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3107 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3110 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3111 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3113 Item
->spSubMenu
->hWnd
= NULL
;
3119 /***********************************************************************
3122 * Display the sub-menu of the selected item of this menu.
3123 * Return the handle of the submenu, or menu if no submenu to display.
3125 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3132 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3134 if (!Menu
) return Menu
;
3136 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3138 Item
= &Menu
->rgItems
[Menu
->iItem
];
3139 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3142 /* message must be sent before using item,
3143 because nearly everything may be changed by the application ! */
3145 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3146 if (!(Flags
& TPM_NONOTIFY
))
3148 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3149 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3150 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3153 Item
= &Menu
->rgItems
[Menu
->iItem
];
3154 //Rect = ItemInfo.Rect;
3155 Rect
.left
= Item
->xItem
;
3156 Rect
.top
= Item
->yItem
;
3157 Rect
.right
= Item
->cxItem
; // Do this for now......
3158 Rect
.bottom
= Item
->cyItem
;
3160 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3162 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3163 if (!(Item
->fState
& MF_HILITE
))
3165 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3166 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3168 NtGdiSelectFont(Dc
, ghMenuFont
);
3170 Item
->fState
|= MF_HILITE
;
3171 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3172 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3174 UserReleaseDC(pWnd
, Dc
, FALSE
);
3177 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3179 Item
->xItem
= Rect
.left
;
3180 Item
->yItem
= Rect
.top
;
3181 Item
->cxItem
= Rect
.right
; // Do this for now......
3182 Item
->cyItem
= Rect
.bottom
;
3184 Item
->fState
|= MF_MOUSESELECT
;
3186 if (IS_SYSTEM_MENU(Menu
))
3188 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3190 NC_GetSysPopupPos(pWnd
, &Rect
);
3191 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3192 Rect
.top
= Rect
.bottom
;
3193 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3194 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3198 IntGetWindowRect(pWnd
, &Rect
);
3199 if (Menu
->fFlags
& MNF_POPUP
)
3202 rc
.left
= Item
->xItem
;
3203 rc
.top
= Item
->yItem
;
3204 rc
.right
= Item
->cxItem
; // Do this for now......
3205 rc
.bottom
= Item
->cyItem
;
3207 MENU_AdjustMenuItemRect(Menu
, &rc
);
3209 /* The first item in the popup menu has to be at the
3210 same y position as the focused menu item */
3211 if(Flags
& TPM_LAYOUTRTL
)
3212 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3214 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3215 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3216 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3217 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3218 - UserGetSystemMetrics(SM_CYBORDER
);
3222 if(Flags
& TPM_LAYOUTRTL
)
3223 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3225 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3226 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3227 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3228 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3232 /* use default alignment for submenus */
3233 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3235 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3237 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3238 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3241 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3243 return Item
->spSubMenu
;
3246 /***********************************************************************
3247 * MenuExecFocusedItem
3249 * Execute a menu item (for instance when user pressed Enter).
3250 * Return the wID of the executed item. Otherwise, -1 indicating
3251 * that no menu item was executed, -2 if a popup is shown;
3252 * Have to receive the flags for the TrackPopupMenu options to avoid
3253 * sending unwanted message.
3256 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3260 TRACE("%p menu=%p\n", pmt
, Menu
);
3262 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3267 Item
= &Menu
->rgItems
[Menu
->iItem
];
3269 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3271 if (!(Item
->spSubMenu
))
3273 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3275 /* If TPM_RETURNCMD is set you return the id, but
3276 do not send a message to the owner */
3277 if (!(Flags
& TPM_RETURNCMD
))
3279 if (Menu
->fFlags
& MNF_SYSMENU
)
3281 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3282 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3286 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3288 if (dwStyle
& MNS_NOTIFYBYPOS
)
3289 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3291 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3299 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3306 /***********************************************************************
3307 * MenuSwitchTracking
3309 * Helper function for menu navigation routines.
3311 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3313 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3315 if ( pmt
->TopMenu
!= PtMenu
&&
3316 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3318 /* both are top level menus (system and menu-bar) */
3319 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3320 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3321 pmt
->TopMenu
= PtMenu
;
3325 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3328 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3331 /***********************************************************************
3334 * Return TRUE if we can go on with menu tracking.
3336 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3338 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3344 if (IS_SYSTEM_MENU(PtMenu
))
3346 item
= PtMenu
->rgItems
;
3350 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3355 if (PtMenu
->iItem
!= id
)
3356 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3358 /* If the popup menu is not already "popped" */
3359 if (!(item
->fState
& MF_MOUSESELECT
))
3361 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3366 /* Else the click was on the menu bar, finish the tracking */
3371 /***********************************************************************
3374 * Return the value of MenuExecFocusedItem if
3375 * the selected item was not a popup. Else open the popup.
3376 * A -1 return value indicates that we go on with menu tracking.
3379 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3381 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3388 if ( IS_SYSTEM_MENU(PtMenu
) )
3390 item
= PtMenu
->rgItems
;
3394 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3397 if (item
&& ( PtMenu
->iItem
== Id
))
3399 if (!(item
->spSubMenu
))
3401 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3402 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3403 return ExecutedMenuId
;
3406 /* If we are dealing with the menu bar */
3407 /* and this is a click on an already "popped" item: */
3408 /* Stop the menu tracking and close the opened submenus */
3409 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3414 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3416 PtMenu
->TimeToHide
= TRUE
;
3422 /***********************************************************************
3425 * Walks menu chain trying to find a menu pt maps to.
3427 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3432 if (!menu
) return NULL
;
3434 /* try subpopup first (if any) */
3435 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3437 pItem
= menu
->rgItems
;
3438 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3439 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3441 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3445 /* check the current window (avoiding WM_HITTEST) */
3448 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3449 INT ht
= GetNCHitEx(pWnd
, pt
);
3450 if ( menu
->fFlags
& MNF_POPUP
)
3452 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3454 else if (ht
== HTSYSMENU
)
3455 ret
= get_win_sys_menu(menu
->hWnd
);
3456 else if (ht
== HTMENU
)
3457 ret
= IntGetMenu( menu
->hWnd
);
3462 /***********************************************************************
3465 * Return TRUE if we can go on with menu tracking.
3467 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3469 UINT Index
= NO_SELECTED_ITEM
;
3473 if (IS_SYSTEM_MENU(PtMenu
))
3476 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3479 if (Index
== NO_SELECTED_ITEM
)
3481 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3483 else if (PtMenu
->iItem
!= Index
)
3485 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3486 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3491 /***********************************************************************
3494 * Return the handle of the selected sub-popup menu (if any).
3496 static PMENU
MENU_GetSubPopup( PMENU menu
)
3500 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3502 item
= &menu
->rgItems
[menu
->iItem
];
3503 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3505 return item
->spSubMenu
;
3510 /***********************************************************************
3513 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3515 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3519 /* When skipping left, we need to do something special after the
3521 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3525 /* When skipping right, for the non-system menu, we need to
3526 handle the last non-special menu item (ie skip any window
3527 icons such as MDI maximize, restore or close) */
3528 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3530 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3531 while (i
< pmt
->TopMenu
->cItems
) {
3532 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3533 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3537 if (i
== pmt
->TopMenu
->cItems
) {
3541 /* When skipping right, we need to cater for the system menu */
3542 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3544 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3551 MDINEXTMENU NextMenu
;
3558 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3559 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3560 NextMenu
.hmenuNext
= NULL
;
3561 NextMenu
.hwndNext
= NULL
;
3562 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3564 TRACE("%p [%p] -> %p [%p]\n",
3565 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3567 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3569 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3570 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3572 /* switch to the menu bar */
3574 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3578 Id
= MenuTmp
->cItems
- 1;
3580 /* Skip backwards over any system predefined icons,
3581 eg. MDI close, restore etc icons */
3583 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3584 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3587 hNewMenu
= UserHMGetHandle(MenuTmp
);
3589 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3591 /* switch to the system menu */
3592 MenuTmp
= get_win_sys_menu(hNewWnd
);
3593 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3598 else /* application returned a new menu to switch to */
3600 hNewMenu
= NextMenu
.hmenuNext
;
3601 hNewWnd
= NextMenu
.hwndNext
;
3603 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3605 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3607 /* get the real system menu */
3608 MenuTmp
= get_win_sys_menu(hNewWnd
);
3609 hNewMenu
= UserHMGetHandle(MenuTmp
);
3611 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3613 /* FIXME: Not sure what to do here;
3614 * perhaps try to track NewMenu as a popup? */
3616 WARN(" -- got confused.\n");
3623 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3625 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3627 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3628 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3631 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3633 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3634 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3635 ///// Use thread pms!!!!
3636 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3637 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3638 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3639 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3642 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3643 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3650 /***********************************************************************
3653 * The idea is not to show the popup if the next input message is
3654 * going to hide it anyway.
3656 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3660 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3662 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3663 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3668 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3669 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3671 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3672 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3673 if( msg
.message
== WM_KEYDOWN
&&
3674 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3676 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3682 /* failures go through this */
3683 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3687 /***********************************************************************
3690 * Handle a VK_ESCAPE key event in a menu.
3692 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3694 BOOL EndMenu
= TRUE
;
3696 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3698 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3700 PMENU MenuPrev
, MenuTmp
;
3702 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3704 /* close topmost popup */
3705 while (MenuTmp
!= pmt
->CurrentMenu
)
3708 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3711 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3712 pmt
->CurrentMenu
= MenuPrev
;
3720 /***********************************************************************
3723 * Handle a VK_LEFT key event in a menu.
3725 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
)
3727 PMENU MenuTmp
, MenuPrev
;
3730 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3732 /* Try to move 1 column left (if possible) */
3733 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3735 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3739 /* close topmost popup */
3740 while (MenuTmp
!= pmt
->CurrentMenu
)
3743 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3746 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3747 pmt
->CurrentMenu
= MenuPrev
;
3749 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3751 /* move menu bar selection if no more popups are left */
3753 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3754 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3756 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3758 /* A sublevel menu was displayed - display the next one
3759 * unless there is another displacement coming up */
3761 if (!MENU_SuspendPopup(pmt
, WM_KEYDOWN
))
3762 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3768 /***********************************************************************
3771 * Handle a VK_RIGHT key event in a menu.
3773 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
)
3778 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3779 pmt
->CurrentMenu
, pmt
->TopMenu
);
3781 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3783 /* If already displaying a popup, try to display sub-popup */
3785 menutmp
= pmt
->CurrentMenu
;
3786 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3788 /* if subpopup was displayed then we are done */
3789 if (menutmp
!= pmt
->CurrentMenu
) return;
3792 /* Check to see if there's another column */
3793 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3795 TRACE("Going to %d.\n", NextCol
);
3796 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3800 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3802 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3804 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3805 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3812 /* try to move to the next item */
3813 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3814 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3816 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3818 if ( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
3819 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3824 /***********************************************************************
3827 * Menu tracking code.
3829 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3830 PWND pwnd
, const RECT
*lprect
)
3834 INT executedMenuId
= -1;
3838 BOOL enterIdleSent
= FALSE
;
3839 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3841 if (pti
!= pwnd
->head
.pti
)
3843 ERR("Not the same PTI!!!!\n");
3847 mt
.CurrentMenu
= pmenu
;
3853 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3854 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3855 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3857 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3859 if (wFlags
& TPM_BUTTONDOWN
)
3861 /* Get the result in order to start the tracking or not */
3862 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3863 fInsideMenuLoop
= fRemove
;
3866 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3868 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3870 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3871 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3872 co_UserSetCapture(NULL
); /* release the capture */
3876 capture_win
= IntGetCapture();
3878 while (fInsideMenuLoop
)
3880 BOOL ErrorExit
= FALSE
;
3881 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3884 /* we have to keep the message in the queue until it's
3885 * clear that menu loop is not over yet. */
3889 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3891 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3892 /* remove the message from the queue */
3893 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3897 /* ReactOS Checks */
3898 if (!VerifyWnd(mt
.OwnerWnd
) ||
3899 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3900 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3901 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3903 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3909 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3910 enterIdleSent
= TRUE
;
3911 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3913 co_IntWaitMessage(NULL
, 0, 0);
3917 if (ErrorExit
) break; // Gracefully dropout.
3919 /* check if EndMenu() tried to cancel us, by posting this message */
3920 if (msg
.message
== WM_CANCELMODE
)
3922 /* we are now out of the loop */
3923 fInsideMenuLoop
= FALSE
;
3925 /* remove the message from the queue */
3926 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3928 /* break out of internal loop, ala ESCAPE */
3932 IntTranslateKbdMessage(&msg
, 0);
3935 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3936 enterIdleSent
=FALSE
;
3939 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3942 * Use the mouse coordinates in lParam instead of those in the MSG
3943 * struct to properly handle synthetic messages. They are already
3944 * in screen coordinates.
3946 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3947 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3949 /* Find a menu for this mouse event */
3950 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3954 /* no WM_NC... messages in captured state */
3956 case WM_RBUTTONDBLCLK
:
3957 case WM_RBUTTONDOWN
:
3958 if (!(wFlags
& TPM_RIGHTBUTTON
))
3960 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3964 case WM_LBUTTONDBLCLK
:
3965 case WM_LBUTTONDOWN
:
3966 /* If the message belongs to the menu, removes it from the queue */
3967 /* Else, end menu tracking */
3968 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3969 fInsideMenuLoop
= fRemove
;
3970 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3971 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3975 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3978 /* Check if a menu was selected by the mouse */
3981 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
3983 /* End the loop if executedMenuId is an item ID */
3984 /* or if the job was done (executedMenuId = 0). */
3985 fRemove
= (executedMenuId
!= -1);
3986 fInsideMenuLoop
= !fRemove
;
3988 /* No menu was selected by the mouse */
3989 /* if the function was called by TrackPopupMenu, continue
3990 with the menu tracking. If not, stop it */
3992 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
3997 /* the selected menu item must be changed every time */
3998 /* the mouse moves. */
4001 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4003 } /* switch(msg.message) - mouse */
4005 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4007 fRemove
= TRUE
; /* Keyboard messages are always removed */
4016 fInsideMenuLoop
= FALSE
;
4021 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4022 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4026 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4027 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4028 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4029 else /* otherwise try to move selection */
4030 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4034 MENU_KeyLeft( &mt
, wFlags
);
4038 MENU_KeyRight( &mt
, wFlags
);
4042 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4048 hi
.cbSize
= sizeof(HELPINFO
);
4049 hi
.iContextType
= HELPINFO_MENUITEM
;
4050 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4053 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4054 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4055 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4056 hi
.MousePos
= msg
.pt
;
4057 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4064 break; /* WM_KEYDOWN */
4072 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4074 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4075 fEndMenu
= (executedMenuId
!= -2);
4076 fInsideMenuLoop
= !fEndMenu
;
4080 /* Hack to avoid control chars. */
4081 /* We will find a better way real soon... */
4082 if (msg
.wParam
< 32) break;
4084 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4086 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4087 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4090 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4091 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4092 fEndMenu
= (executedMenuId
!= -2);
4093 fInsideMenuLoop
= !fEndMenu
;
4097 } /* switch(msg.message) - kbd */
4101 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4102 IntDispatchMessage( &msg
);
4106 if (fInsideMenuLoop
) fRemove
= TRUE
;
4108 /* finally remove message from the queue */
4110 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4111 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4112 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4115 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4116 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4117 co_UserSetCapture(NULL
); /* release the capture */
4119 /* If dropdown is still painted and the close box is clicked on
4120 then the menu will be destroyed as part of the DispatchMessage above.
4121 This will then invalidate the menu handle in mt.hTopMenu. We should
4122 check for this first. */
4123 if ( VerifyMenu( mt
.TopMenu
) )
4125 if (VerifyWnd(mt
.OwnerWnd
))
4127 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4129 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4131 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4132 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4134 co_UserDestroyWindow(pwndTM
);
4135 mt
.TopMenu
->hWnd
= NULL
;
4137 if (!(wFlags
& TPM_NONOTIFY
))
4139 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4140 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4143 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4144 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4147 /* Reset the variable for hiding menu */
4148 mt
.TopMenu
->TimeToHide
= FALSE
;
4151 /* The return value is only used by TrackPopupMenu */
4152 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4153 if (executedMenuId
== -1) executedMenuId
= 0;
4154 return executedMenuId
;
4157 /***********************************************************************
4160 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4163 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4165 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4167 co_UserHideCaret(0);
4169 /* This makes the menus of applications built with Delphi work.
4170 * It also enables menus to be displayed in more than one window,
4171 * but there are some bugs left that need to be fixed in this case.
4175 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4179 top_popup
= Menu
->hWnd
;
4180 top_popup_hmenu
= UserHMGetHandle(Menu
);
4183 fInsideMenuLoop
= TRUE
;
4186 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4187 if (!(wFlags
& TPM_NONOTIFY
))
4189 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4193 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4195 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4196 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4197 co_UserSetCapture(capture_win
); // 2
4198 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4200 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4202 if (!(wFlags
& TPM_NONOTIFY
))
4204 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4205 /* If an app changed/recreated menu bar entries in WM_INITMENU
4206 * menu sizes will be recalculated once the menu created/shown.
4210 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4212 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4217 /***********************************************************************
4220 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4222 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4224 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4226 if (!(wFlags
& TPM_NONOTIFY
))
4227 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4229 co_UserShowCaret(0);
4232 top_popup_hmenu
= NULL
;
4237 /***********************************************************************
4238 * MenuTrackMouseMenuBar
4240 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4242 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4244 PMENU pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4245 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4247 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4249 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4250 if (VerifyMenu(pMenu
))
4252 /* map point to parent client coordinates */
4253 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4254 if (Parent
!= UserGetDesktopWindow())
4256 IntScreenToClient(Parent
, &pt
);
4259 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4260 /* fetch the window menu again, it may have changed */
4261 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4262 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4263 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4267 /***********************************************************************
4268 * MenuTrackKbdMenuBar
4270 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4272 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4274 UINT uItem
= NO_SELECTED_ITEM
;
4276 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4278 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4280 /* find window that has a menu */
4282 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4283 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4285 /* check if we have to track a system menu */
4287 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4288 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4290 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4291 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4293 wParam
|= HTSYSMENU
; /* prevent item lookup */
4296 if (!VerifyMenu( TrackMenu
)) return;
4298 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4300 /* fetch the window menu again, it may have changed */
4301 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4303 if( wChar
&& wChar
!= ' ' )
4305 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4306 if ( uItem
>= (UINT
)(-2) )
4308 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4309 /* schedule end of menu tracking */
4310 wFlags
|= TF_ENDMENU
;
4315 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4317 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4319 if( uItem
== NO_SELECTED_ITEM
)
4320 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4322 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4326 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4327 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4330 /**********************************************************************
4331 * TrackPopupMenuEx (USER32.@)
4333 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4334 PWND pWnd
, LPTPMPARAMS lpTpm
)
4337 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4339 if (pti
!= pWnd
->head
.pti
)
4341 ERR("Must be the same pti!\n");
4345 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4346 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4347 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4349 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4351 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4355 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4357 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4359 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4360 if (!(wFlags
& TPM_NONOTIFY
))
4362 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4365 if (menu
->fFlags
& MNF_SYSMENU
)
4366 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4368 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4369 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4370 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4373 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4374 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4375 co_UserSetCapture(NULL
); /* release the capture */
4379 // HACK : Until back trace fault in co_IntUpdateWindows and MENU_TrackMenu.
4381 if (EngGetLastError() == ERROR_ACCESS_DENIED
)
4383 EngSetLastError(NO_ERROR
);
4386 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4390 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4391 if (pwndM
) // wine hack around this with their destroy function.
4392 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4395 if (!(wFlags
& TPM_NONOTIFY
))
4397 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4398 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4416 PPOPUPMENU pPopupMenu
;
4420 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4426 if (Message
!= WM_NCCREATE
)
4428 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4431 Wnd
->fnid
= FNID_MENU
;
4432 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4433 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4434 pPopupMenu
->spwndPopupMenu
= Wnd
;
4435 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4436 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4442 if (Wnd
->fnid
!= FNID_MENU
)
4444 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4447 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4455 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4456 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4460 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4461 *lResult
= MA_NOACTIVATE
;
4467 IntBeginPaint(Wnd
, &ps
);
4468 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4469 IntEndPaint(Wnd
, &ps
);
4473 case WM_PRINTCLIENT
:
4475 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4484 /* zero out global pointer in case resident popup window was destroyed. */
4487 if (UserHMGetHandle(Wnd
) == top_popup
)
4490 top_popup_hmenu
= NULL
;
4495 ERR("No Window Pop Up!\n");
4501 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4502 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4503 Wnd
->fnid
= FNID_DESTROY
;
4507 case MM_SETMENUHANDLE
: // wine'isms
4510 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4513 ERR("Bad Menu Handle\n");
4516 pPopupMenu
->spmenu
= pmenu
;
4520 case MM_GETMENUHANDLE
: // wine'isms
4522 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4526 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4528 ERR("Someone is passing unknown menu messages %d\n",Message
);
4530 TRACE("PMWP to IDWP %d\n",Message
);
4531 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4539 IntHiliteMenuItem(PWND WindowObject
,
4545 UINT uItem
= uItemHilite
;
4547 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4549 if (uHilite
& MF_HILITE
)
4551 MenuItem
->fState
|= MF_HILITE
;
4555 MenuItem
->fState
&= ~MF_HILITE
;
4557 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4558 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4559 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4561 return TRUE
; // Always returns true!!!!
4565 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4569 DWORD dwExStyle
= 0;
4570 BOOLEAN retValue
= TRUE
;
4572 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4574 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4576 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4578 dwStyle
= pWindowObject
->style
;
4579 dwExStyle
= pWindowObject
->ExStyle
;
4581 bti
->rcTitleBar
.top
= 0;
4582 bti
->rcTitleBar
.left
= 0;
4583 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4584 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4586 /* Is it iconiced ? */
4587 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4589 /* Remove frame from rectangle */
4590 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4592 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4593 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4595 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4597 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4598 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4600 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4602 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4603 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4606 /* We have additional border information if the window
4607 * is a child (but not an MDI child) */
4608 if ( (dwStyle
& WS_CHILD
) &&
4609 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4611 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4613 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4614 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4617 if (dwExStyle
& WS_EX_STATICEDGE
)
4619 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4620 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4625 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4626 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4627 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4629 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4630 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4632 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4633 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4637 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4638 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4639 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4642 if (dwStyle
& WS_CAPTION
)
4644 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4645 if (dwStyle
& WS_SYSMENU
)
4647 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4649 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4650 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4654 if (!(dwStyle
& WS_MINIMIZEBOX
))
4656 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4658 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4660 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4664 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4666 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4668 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4670 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4675 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4676 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4677 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4678 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4683 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4688 EngSetLastError(ERROR_INVALID_PARAMETER
);
4700 LPCMENUITEMINFOW UnsafeItemInfo
,
4701 PUNICODE_STRING lpstr
)
4704 ROSMENUITEMINFO ItemInfo
;
4706 /* Try to copy the whole MENUITEMINFOW structure */
4707 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4708 if (NT_SUCCESS(Status
))
4710 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4711 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4713 EngSetLastError(ERROR_INVALID_PARAMETER
);
4716 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4719 /* Try to copy without last field (not present in older versions) */
4720 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4721 if (NT_SUCCESS(Status
))
4723 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4725 EngSetLastError(ERROR_INVALID_PARAMETER
);
4728 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4729 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4732 SetLastNtError(Status
);
4736 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4741 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4746 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4748 if (pItem
->spSubMenu
)
4750 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4753 return (pItem
->fType
| pItem
->fState
);
4756 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4761 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4766 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4768 if (pItem
->spSubMenu
)
4770 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4776 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4778 PMENU menu
, pSubTarget
;
4780 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4781 return NO_SELECTED_ITEM
;
4783 pSubTarget
= UserGetMenuObject(hSubTarget
);
4785 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4787 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4793 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4795 PWINSTATION_OBJECT WinStaObject
;
4799 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4801 if (gpepCSRSS
!= CurrentProcess
)
4804 * gpepCSRSS does not have a Win32WindowStation
4807 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4813 if (!NT_SUCCESS(Status
))
4815 ERR("Validation of window station handle (%p) failed\n",
4816 CurrentProcess
->Win32WindowStation
);
4817 SetLastNtError(Status
);
4820 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4821 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4823 ERR("Desktop Window Station does not match Process one!\n");
4825 ObDereferenceObject(WinStaObject
);
4829 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4832 if (Menu
) UserDereferenceObject(Menu
);
4833 return (HMENU
)Handle
;
4841 PROSMENUITEMINFO ItemInfo
,
4843 PUNICODE_STRING lpstr
)
4848 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4850 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4855 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4859 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4869 PROSMENUITEMINFO UnsafeItemInfo
,
4871 PUNICODE_STRING lpstr
)
4874 ROSMENUITEMINFO ItemInfo
;
4879 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4880 if (! NT_SUCCESS(Status
))
4882 SetLastNtError(Status
);
4885 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4886 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4887 Size
!= sizeof(ROSMENUITEMINFO
) )
4889 EngSetLastError(ERROR_INVALID_PARAMETER
);
4892 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4893 if (! NT_SUCCESS(Status
))
4895 SetLastNtError(Status
);
4898 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4900 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4901 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4903 EngSetLastError(ERROR_INVALID_PARAMETER
);
4907 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4909 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4910 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4913 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4919 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4923 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4926 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4927 if (! NT_SUCCESS(Status
))
4929 SetLastNtError(Status
);
4941 PROSMENUINFO UnsafeMenuInfo
,
4947 ROSMENUINFO MenuInfo
;
4949 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4950 if (! NT_SUCCESS(Status
))
4952 SetLastNtError(Status
);
4955 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4957 EngSetLastError(ERROR_INVALID_PARAMETER
);
4960 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4961 if (! NT_SUCCESS(Status
))
4963 SetLastNtError(Status
);
4970 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4975 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4978 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
4979 if (! NT_SUCCESS(Status
))
4981 SetLastNtError(Status
);
5001 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5003 Rect
->left
= MenuItem
->xItem
;
5004 Rect
->top
= MenuItem
->yItem
;
5005 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5006 Rect
->bottom
= MenuItem
->cyItem
;
5010 ERR("Failed Item Lookup! %u\n", uItem
);
5016 HWND hWnd
= Menu
->hWnd
;
5017 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5020 if (Menu
->fFlags
& MNF_POPUP
)
5022 XMove
= pWnd
->rcClient
.left
;
5023 YMove
= pWnd
->rcClient
.top
;
5027 XMove
= pWnd
->rcWindow
.left
;
5028 YMove
= pWnd
->rcWindow
.top
;
5031 Rect
->left
+= XMove
;
5033 Rect
->right
+= XMove
;
5034 Rect
->bottom
+= YMove
;
5039 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5041 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5042 HMENU hSysMenu
, hNewMenu
= NULL
;
5043 ROSMENUITEMINFO ItemInfoSet
= {0};
5044 ROSMENUITEMINFO ItemInfo
= {0};
5045 UNICODE_STRING MenuName
;
5047 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5048 if (NULL
== hSysMenu
)
5052 SysMenu
= UserGetMenuObject(hSysMenu
);
5053 if (NULL
== SysMenu
)
5055 UserDestroyMenu(hSysMenu
);
5059 SysMenu
->fFlags
|= MNF_SYSMENU
;
5060 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5064 //hNewMenu = co_IntLoadSysMenuTemplate();
5065 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5067 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5068 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5072 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5073 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5074 //ERR("%wZ\n",&MenuName);
5079 IntReleaseMenuObject(SysMenu
);
5080 UserDestroyMenu(hSysMenu
);
5083 Menu
= UserGetMenuObject(hNewMenu
);
5086 IntReleaseMenuObject(SysMenu
);
5087 UserDestroyMenu(hSysMenu
);
5091 // Do the rest in here.
5093 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5095 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5096 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5097 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5098 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5099 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5100 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5101 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5102 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5103 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5104 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5106 NewMenu
= IntCloneMenu(Menu
);
5108 IntReleaseMenuObject(NewMenu
);
5109 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5111 IntDestroyMenuObject(Menu
, FALSE
);
5119 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5121 if (Window
->pcls
->style
& CS_NOCLOSE
)
5122 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5124 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5125 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5126 ItemInfo
.fType
= MF_POPUP
;
5127 ItemInfo
.fState
= MFS_ENABLED
;
5128 ItemInfo
.dwTypeData
= NULL
;
5130 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5131 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5135 ERR("failed to load system menu!\n");
5140 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5146 if (Window
->SystemMenu
)
5148 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5149 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5151 IntDestroyMenuObject(Menu
, TRUE
);
5152 Window
->SystemMenu
= NULL
;
5158 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5159 if ((!Window
->SystemMenu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5161 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5162 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5166 if (Window
->SystemMenu
)
5168 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5169 /* Store the dummy sysmenu handle to facilitate the refresh */
5170 /* of the close button if the SC_CLOSE item change */
5171 Menu
= UserGetMenuObject(hMenu
);
5174 Menu
->spwndNotify
= Window
;
5175 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5183 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5187 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5189 if (Window
->SystemMenu
)
5191 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5194 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5195 IntDestroyMenuObject(OldMenu
, TRUE
);
5199 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5201 { // Use spmenuSys too!
5202 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5205 Window
->SystemMenu
= NULL
;
5207 if (Menu
&& Window
!= Menu
->spwndNotify
)
5209 Menu
->spwndNotify
= Window
;
5221 PMENU OldMenu
, NewMenu
= NULL
;
5223 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5225 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5226 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5230 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5238 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5239 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5248 NewMenu
= IntGetMenuObject(Menu
);
5249 if (NULL
== NewMenu
)
5251 if (NULL
!= OldMenu
)
5253 IntReleaseMenuObject(OldMenu
);
5255 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5258 if (NULL
!= NewMenu
->hWnd
)
5260 /* Can't use the same menu for two windows */
5261 if (NULL
!= OldMenu
)
5263 IntReleaseMenuObject(OldMenu
);
5265 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5271 Wnd
->IDMenu
= (UINT
) Menu
;
5272 if (NULL
!= NewMenu
)
5274 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5275 IntReleaseMenuObject(NewMenu
);
5277 if (NULL
!= OldMenu
)
5279 OldMenu
->hWnd
= NULL
;
5280 IntReleaseMenuObject(OldMenu
);
5287 /* FUNCTIONS *****************************************************************/
5293 NtUserCheckMenuItem(
5299 DECLARE_RETURN(DWORD
);
5301 TRACE("Enter NtUserCheckMenuItem\n");
5302 UserEnterExclusive();
5304 if(!(Menu
= UserGetMenuObject(hMenu
)))
5309 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5312 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5327 DECLARE_RETURN(BOOL
);
5329 TRACE("Enter NtUserDeleteMenu\n");
5330 UserEnterExclusive();
5332 if(!(Menu
= UserGetMenuObject(hMenu
)))
5337 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5340 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5346 * NtUserGetSystemMenu
5348 * The NtUserGetSystemMenu function allows the application to access the
5349 * window menu (also known as the system menu or the control menu) for
5350 * copying and modifying.
5354 * Handle to the window that will own a copy of the window menu.
5356 * Specifies the action to be taken. If this parameter is FALSE,
5357 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5358 * currently in use. The copy is initially identical to the window menu
5359 * but it can be modified.
5360 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5361 * to the default state. The previous window menu, if any, is destroyed.
5364 * If the bRevert parameter is FALSE, the return value is a handle to a
5365 * copy of the window menu. If the bRevert parameter is TRUE, the return
5373 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5377 DECLARE_RETURN(HMENU
);
5379 TRACE("Enter NtUserGetSystemMenu\n");
5382 if (!(Window
= UserGetWindowObject(hWnd
)))
5387 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5392 RETURN(Menu
->head
.h
);
5395 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5401 * NtUserSetSystemMenu
5408 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5410 BOOL Result
= FALSE
;
5413 DECLARE_RETURN(BOOL
);
5415 TRACE("Enter NtUserSetSystemMenu\n");
5416 UserEnterExclusive();
5418 if (!(Window
= UserGetWindowObject(hWnd
)))
5426 * Assign new menu handle and Up the Lock Count.
5428 if (!(Menu
= IntGetMenuObject(hMenu
)))
5433 Result
= IntSetSystemMenu(Window
, Menu
);
5436 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5441 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5450 NtUserGetTitleBarInfo(
5455 TITLEBARINFO bartitleinfo
;
5456 DECLARE_RETURN(BOOLEAN
);
5457 BOOLEAN retValue
= TRUE
;
5459 TRACE("Enter NtUserGetTitleBarInfo\n");
5460 UserEnterExclusive();
5462 /* Vaildate the windows handle */
5463 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5465 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5471 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5472 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5473 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5475 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5477 /* Fail copy the data */
5478 EngSetLastError(ERROR_INVALID_PARAMETER
);
5483 /* Get the tile bar info */
5486 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5491 /* Copy our buffer to user mode buffer bti */
5492 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5493 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5495 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5497 /* Fail copy the data */
5498 EngSetLastError(ERROR_INVALID_PARAMETER
);
5508 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5516 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5519 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5521 if(!(Menu
= UserGetMenuObject(hMenu
)))
5526 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5528 EngSetLastError(ERROR_ACCESS_DENIED
);
5531 return IntDestroyMenuObject(Menu
, FALSE
);
5542 DECLARE_RETURN(BOOL
);
5544 TRACE("Enter NtUserDestroyMenu\n");
5545 UserEnterExclusive();
5547 if(!(Menu
= UserGetMenuObject(hMenu
)))
5551 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5553 EngSetLastError(ERROR_ACCESS_DENIED
);
5556 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5559 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5568 NtUserEnableMenuItem(
5574 DECLARE_RETURN(UINT
);
5576 TRACE("Enter NtUserEnableMenuItem\n");
5577 UserEnterExclusive();
5579 if(!(Menu
= UserGetMenuObject(hMenu
)))
5584 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5587 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5599 TRACE("Enter NtUserEndMenu\n");
5600 UserEnterExclusive();
5601 /* if ( gptiCurrent->pMenuState &&
5602 gptiCurrent->pMenuState->pGlobalPopupMenu )
5604 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5607 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5610 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5612 if (fInsideMenuLoop
&& top_popup
)
5614 fInsideMenuLoop
= FALSE
;
5615 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5618 TRACE("Leave NtUserEndMenu\n");
5626 NtUserGetMenuBarInfo(
5636 PPOPUPMENU pPopupMenu
;
5637 USER_REFERENCE_ENTRY Ref
;
5638 NTSTATUS Status
= STATUS_SUCCESS
;
5640 DECLARE_RETURN(BOOL
);
5642 TRACE("Enter NtUserGetMenuBarInfo\n");
5645 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5647 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5651 UserRefObjectCo(pWnd
, &Ref
);
5653 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5655 kmbi
.hwndMenu
= NULL
;
5656 kmbi
.fBarFocused
= FALSE
;
5657 kmbi
.fFocused
= FALSE
;
5662 if (!pWnd
->pcls
->fnid
)
5664 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5666 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5667 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5670 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5671 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5672 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5673 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5675 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5677 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5682 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5683 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5684 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5687 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5688 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5689 hMenu
= UserHMGetHandle(Menu
);
5700 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5701 kmbi
.cbSize
= pmbi
->cbSize
;
5703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5709 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5711 EngSetLastError(ERROR_INVALID_PARAMETER
);
5715 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5719 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5724 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5725 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5726 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5727 TRACE("idItem a 0 %d\n",Ret
);
5731 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5732 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5736 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5737 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5740 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5741 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5743 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5748 kmbi
.fFocused
= kmbi
.fBarFocused
;
5753 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5754 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5758 Status
= _SEH2_GetExceptionCode();
5762 if (!NT_SUCCESS(Status
))
5764 SetLastNtError(Status
);
5771 if (pWnd
) UserDerefObjectCo(pWnd
);
5772 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5785 PMENU Menu
, SubMenu
;
5788 DECLARE_RETURN(UINT
);
5790 TRACE("Enter NtUserGetMenuIndex\n");
5793 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5794 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5797 MenuItem
= Menu
->rgItems
;
5798 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5800 if (MenuItem
->spSubMenu
== SubMenu
)
5801 RETURN(MenuItem
->wID
);
5806 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5815 NtUserGetMenuItemRect(
5826 NTSTATUS Status
= STATUS_SUCCESS
;
5827 DECLARE_RETURN(BOOL
);
5829 TRACE("Enter NtUserGetMenuItemRect\n");
5832 if (!(Menu
= UserGetMenuObject(hMenu
)))
5837 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5839 Rect
.left
= MenuItem
->xItem
;
5840 Rect
.top
= MenuItem
->yItem
;
5841 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5842 Rect
.bottom
= MenuItem
->cyItem
;
5852 if (lprcItem
== NULL
) RETURN( FALSE
);
5854 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5856 if (Menu
->fFlags
& MNF_POPUP
)
5858 XMove
= ReferenceWnd
->rcClient
.left
;
5859 YMove
= ReferenceWnd
->rcClient
.top
;
5863 XMove
= ReferenceWnd
->rcWindow
.left
;
5864 YMove
= ReferenceWnd
->rcWindow
.top
;
5869 Rect
.right
+= XMove
;
5870 Rect
.bottom
+= YMove
;
5874 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5876 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5878 Status
= _SEH2_GetExceptionCode();
5882 if (!NT_SUCCESS(Status
))
5884 SetLastNtError(Status
);
5890 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5899 NtUserHiliteMenuItem(
5907 DECLARE_RETURN(BOOLEAN
);
5909 TRACE("Enter NtUserHiliteMenuItem\n");
5910 UserEnterExclusive();
5912 if(!(Window
= UserGetWindowObject(hWnd
)))
5914 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5918 if(!(Menu
= UserGetMenuObject(hMenu
)))
5920 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5924 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
5927 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
5937 NtUserDrawMenuBarTemp(
5947 NTSTATUS Status
= STATUS_SUCCESS
;
5948 DECLARE_RETURN(DWORD
);
5950 ERR("Enter NtUserDrawMenuBarTemp\n");
5951 UserEnterExclusive();
5953 if(!(Window
= UserGetWindowObject(hWnd
)))
5955 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5959 if(!(Menu
= UserGetMenuObject(hMenu
)))
5961 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5967 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
5968 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
5970 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5972 Status
= _SEH2_GetExceptionCode();
5976 if (Status
!= STATUS_SUCCESS
)
5978 SetLastNtError(Status
);
5982 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
5985 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
5994 NtUserMenuItemFromPoint(
6004 DECLARE_RETURN(int);
6006 TRACE("Enter NtUserMenuItemFromPoint\n");
6007 UserEnterExclusive();
6009 if (!(Menu
= UserGetMenuObject(hMenu
)))
6014 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6019 X
-= Window
->rcWindow
.left
;
6020 Y
-= Window
->rcWindow
.top
;
6023 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6027 Rect
.left
= mi
->xItem
;
6028 Rect
.top
= mi
->yItem
;
6029 Rect
.right
= mi
->cxItem
;
6030 Rect
.bottom
= mi
->cyItem
;
6032 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6034 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6040 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6043 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6059 DECLARE_RETURN(BOOL
);
6061 TRACE("Enter NtUserRemoveMenu\n");
6062 UserEnterExclusive();
6064 if(!(Menu
= UserGetMenuObject(hMenu
)))
6069 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6072 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6089 DECLARE_RETURN(BOOL
);
6091 TRACE("Enter NtUserSetMenu\n");
6092 UserEnterExclusive();
6094 if (!(Window
= UserGetWindowObject(hWnd
)))
6099 if (!IntSetMenu(Window
, Menu
, &Changed
))
6104 // Not minimized and please repaint!!!
6105 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6107 USER_REFERENCE_ENTRY Ref
;
6108 UserRefObjectCo(Window
, &Ref
);
6109 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6110 UserDerefObjectCo(Window
);
6116 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6125 NtUserSetMenuContextHelpId(
6127 DWORD dwContextHelpId
)
6130 DECLARE_RETURN(BOOL
);
6132 TRACE("Enter NtUserSetMenuContextHelpId\n");
6133 UserEnterExclusive();
6135 if(!(Menu
= UserGetMenuObject(hMenu
)))
6140 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6143 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6152 NtUserSetMenuDefaultItem(
6158 DECLARE_RETURN(BOOL
);
6160 TRACE("Enter NtUserSetMenuDefaultItem\n");
6161 UserEnterExclusive();
6163 if(!(Menu
= UserGetMenuObject(hMenu
)))
6168 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6171 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6180 NtUserSetMenuFlagRtoL(
6184 DECLARE_RETURN(BOOL
);
6186 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6187 UserEnterExclusive();
6189 if(!(Menu
= UserGetMenuObject(hMenu
)))
6194 RETURN(IntSetMenuFlagRtoL(Menu
));
6197 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6206 NtUserThunkedMenuInfo(
6211 DECLARE_RETURN(BOOL
);
6213 TRACE("Enter NtUserThunkedMenuInfo\n");
6214 UserEnterExclusive();
6216 if (!(Menu
= UserGetMenuObject(hMenu
)))
6221 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6224 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6233 NtUserThunkedMenuItemInfo(
6238 LPMENUITEMINFOW lpmii
,
6239 PUNICODE_STRING lpszCaption
)
6243 UNICODE_STRING lstrCaption
;
6244 DECLARE_RETURN(BOOL
);
6246 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6247 UserEnterExclusive();
6249 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6250 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6252 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6254 if (!(Menu
= UserGetMenuObject(hMenu
)))
6259 /* Check if we got a Caption */
6260 if (lpszCaption
&& lpszCaption
->Buffer
)
6262 /* Copy the string to kernel mode */
6263 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6266 if (!NT_SUCCESS(Status
))
6268 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6269 SetLastNtError(Status
);
6274 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6276 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6279 if (lstrCaption
.Buffer
)
6281 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6284 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6293 NtUserTrackPopupMenuEx(
6305 USER_REFERENCE_ENTRY Ref
;
6307 TRACE("Enter NtUserTrackPopupMenuEx\n");
6308 UserEnterExclusive();
6309 /* Parameter check */
6310 if (!(menu
= UserGetMenuObject( hMenu
)))
6312 ERR("TPME : Invalid Menu handle.\n");
6313 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6317 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6319 ERR("TPME : Invalid Window handle.\n");
6327 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6332 _SEH2_YIELD(goto Exit
);
6336 UserRefObjectCo(pWnd
, &Ref
);
6337 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6338 UserDerefObjectCo(pWnd
);
6341 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);