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 //// ReactOS only HACK: CORE-2338
3477 // Windows tracks mouse moves to the system menu but does not open it.
3478 // Only keyboard tracking can do that.
3480 TRACE("SystemMenu\n");
3481 return TRUE
; // Stay inside the Loop!
3484 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3487 if (Index
== NO_SELECTED_ITEM
)
3489 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3491 else if (PtMenu
->iItem
!= Index
)
3493 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3494 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3499 /***********************************************************************
3502 * Return the handle of the selected sub-popup menu (if any).
3504 static PMENU
MENU_GetSubPopup( PMENU menu
)
3508 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3510 item
= &menu
->rgItems
[menu
->iItem
];
3511 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3513 return item
->spSubMenu
;
3518 /***********************************************************************
3521 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3523 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3527 /* When skipping left, we need to do something special after the
3529 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3533 /* When skipping right, for the non-system menu, we need to
3534 handle the last non-special menu item (ie skip any window
3535 icons such as MDI maximize, restore or close) */
3536 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3538 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3539 while (i
< pmt
->TopMenu
->cItems
) {
3540 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3541 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3545 if (i
== pmt
->TopMenu
->cItems
) {
3549 /* When skipping right, we need to cater for the system menu */
3550 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3552 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3559 MDINEXTMENU NextMenu
;
3566 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3567 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3568 NextMenu
.hmenuNext
= NULL
;
3569 NextMenu
.hwndNext
= NULL
;
3570 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3572 TRACE("%p [%p] -> %p [%p]\n",
3573 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3575 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3577 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3578 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3580 /* switch to the menu bar */
3582 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3586 Id
= MenuTmp
->cItems
- 1;
3588 /* Skip backwards over any system predefined icons,
3589 eg. MDI close, restore etc icons */
3591 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3592 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3595 hNewMenu
= UserHMGetHandle(MenuTmp
);
3597 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3599 /* switch to the system menu */
3600 MenuTmp
= get_win_sys_menu(hNewWnd
);
3601 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3606 else /* application returned a new menu to switch to */
3608 hNewMenu
= NextMenu
.hmenuNext
;
3609 hNewWnd
= NextMenu
.hwndNext
;
3611 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3613 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3615 /* get the real system menu */
3616 MenuTmp
= get_win_sys_menu(hNewWnd
);
3617 hNewMenu
= UserHMGetHandle(MenuTmp
);
3619 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3621 /* FIXME: Not sure what to do here;
3622 * perhaps try to track NewMenu as a popup? */
3624 WARN(" -- got confused.\n");
3631 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3633 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3635 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3636 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3639 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3641 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3642 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3643 ///// Use thread pms!!!!
3644 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3645 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3646 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3647 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3650 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3651 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3658 /***********************************************************************
3661 * The idea is not to show the popup if the next input message is
3662 * going to hide it anyway.
3664 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3668 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3670 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3671 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3676 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3677 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3679 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3680 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3681 if( msg
.message
== WM_KEYDOWN
&&
3682 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3684 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3690 /* failures go through this */
3691 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3695 /***********************************************************************
3698 * Handle a VK_ESCAPE key event in a menu.
3700 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3702 BOOL EndMenu
= TRUE
;
3704 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3706 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3708 PMENU MenuPrev
, MenuTmp
;
3710 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3712 /* close topmost popup */
3713 while (MenuTmp
!= pmt
->CurrentMenu
)
3716 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3719 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3720 pmt
->CurrentMenu
= MenuPrev
;
3728 /***********************************************************************
3731 * Handle a VK_LEFT key event in a menu.
3733 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
)
3735 PMENU MenuTmp
, MenuPrev
;
3738 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3740 /* Try to move 1 column left (if possible) */
3741 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3743 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3747 /* close topmost popup */
3748 while (MenuTmp
!= pmt
->CurrentMenu
)
3751 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3754 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3755 pmt
->CurrentMenu
= MenuPrev
;
3757 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3759 /* move menu bar selection if no more popups are left */
3761 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3762 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3764 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3766 /* A sublevel menu was displayed - display the next one
3767 * unless there is another displacement coming up */
3769 if (!MENU_SuspendPopup(pmt
, WM_KEYDOWN
))
3770 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3776 /***********************************************************************
3779 * Handle a VK_RIGHT key event in a menu.
3781 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
)
3786 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3787 pmt
->CurrentMenu
, pmt
->TopMenu
);
3789 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3791 /* If already displaying a popup, try to display sub-popup */
3793 menutmp
= pmt
->CurrentMenu
;
3794 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3796 /* if subpopup was displayed then we are done */
3797 if (menutmp
!= pmt
->CurrentMenu
) return;
3800 /* Check to see if there's another column */
3801 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3803 TRACE("Going to %d.\n", NextCol
);
3804 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3808 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3810 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3812 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3813 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3820 /* try to move to the next item */
3821 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3822 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3824 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3826 if ( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
3827 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3832 /***********************************************************************
3835 * Menu tracking code.
3837 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3838 PWND pwnd
, const RECT
*lprect
)
3842 INT executedMenuId
= -1;
3846 BOOL enterIdleSent
= FALSE
;
3847 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3849 if (pti
!= pwnd
->head
.pti
)
3851 ERR("Not the same PTI!!!!\n");
3855 mt
.CurrentMenu
= pmenu
;
3861 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3862 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3863 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3865 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3867 if (wFlags
& TPM_BUTTONDOWN
)
3869 /* Get the result in order to start the tracking or not */
3870 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3871 fInsideMenuLoop
= fRemove
;
3874 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3876 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3878 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3879 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3880 co_UserSetCapture(NULL
); /* release the capture */
3884 capture_win
= IntGetCapture();
3886 while (fInsideMenuLoop
)
3888 BOOL ErrorExit
= FALSE
;
3889 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3892 /* we have to keep the message in the queue until it's
3893 * clear that menu loop is not over yet. */
3897 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3899 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3900 /* remove the message from the queue */
3901 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3905 /* ReactOS Checks */
3906 if (!VerifyWnd(mt
.OwnerWnd
) ||
3907 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3908 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3909 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3911 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3917 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3918 enterIdleSent
= TRUE
;
3919 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3921 co_IntWaitMessage(NULL
, 0, 0);
3925 if (ErrorExit
) break; // Gracefully dropout.
3927 /* check if EndMenu() tried to cancel us, by posting this message */
3928 if (msg
.message
== WM_CANCELMODE
)
3930 /* we are now out of the loop */
3931 fInsideMenuLoop
= FALSE
;
3933 /* remove the message from the queue */
3934 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3936 /* break out of internal loop, ala ESCAPE */
3940 IntTranslateKbdMessage(&msg
, 0);
3943 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3944 enterIdleSent
=FALSE
;
3947 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3950 * Use the mouse coordinates in lParam instead of those in the MSG
3951 * struct to properly handle synthetic messages. They are already
3952 * in screen coordinates.
3954 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3955 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3957 /* Find a menu for this mouse event */
3958 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3962 /* no WM_NC... messages in captured state */
3964 case WM_RBUTTONDBLCLK
:
3965 case WM_RBUTTONDOWN
:
3966 if (!(wFlags
& TPM_RIGHTBUTTON
))
3968 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3972 case WM_LBUTTONDBLCLK
:
3973 case WM_LBUTTONDOWN
:
3974 /* If the message belongs to the menu, removes it from the queue */
3975 /* Else, end menu tracking */
3976 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3977 fInsideMenuLoop
= fRemove
;
3978 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3979 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3983 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3986 /* Check if a menu was selected by the mouse */
3989 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
3991 /* End the loop if executedMenuId is an item ID */
3992 /* or if the job was done (executedMenuId = 0). */
3993 fRemove
= (executedMenuId
!= -1);
3994 fInsideMenuLoop
= !fRemove
;
3996 /* No menu was selected by the mouse */
3997 /* if the function was called by TrackPopupMenu, continue
3998 with the menu tracking. If not, stop it */
4000 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4005 /* the selected menu item must be changed every time */
4006 /* the mouse moves. */
4009 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4011 } /* switch(msg.message) - mouse */
4013 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4015 fRemove
= TRUE
; /* Keyboard messages are always removed */
4024 fInsideMenuLoop
= FALSE
;
4029 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4030 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4034 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4035 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4036 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4037 else /* otherwise try to move selection */
4038 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4042 MENU_KeyLeft( &mt
, wFlags
);
4046 MENU_KeyRight( &mt
, wFlags
);
4050 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4056 hi
.cbSize
= sizeof(HELPINFO
);
4057 hi
.iContextType
= HELPINFO_MENUITEM
;
4058 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4061 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4062 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4063 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4064 hi
.MousePos
= msg
.pt
;
4065 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4072 break; /* WM_KEYDOWN */
4080 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4082 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4083 fEndMenu
= (executedMenuId
!= -2);
4084 fInsideMenuLoop
= !fEndMenu
;
4088 /* Hack to avoid control chars. */
4089 /* We will find a better way real soon... */
4090 if (msg
.wParam
< 32) break;
4092 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4094 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4095 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4098 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4099 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4100 fEndMenu
= (executedMenuId
!= -2);
4101 fInsideMenuLoop
= !fEndMenu
;
4105 } /* switch(msg.message) - kbd */
4109 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4110 IntDispatchMessage( &msg
);
4114 if (fInsideMenuLoop
) fRemove
= TRUE
;
4116 /* finally remove message from the queue */
4118 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4119 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4120 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4123 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4124 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4125 co_UserSetCapture(NULL
); /* release the capture */
4127 /* If dropdown is still painted and the close box is clicked on
4128 then the menu will be destroyed as part of the DispatchMessage above.
4129 This will then invalidate the menu handle in mt.hTopMenu. We should
4130 check for this first. */
4131 if ( VerifyMenu( mt
.TopMenu
) )
4133 if (VerifyWnd(mt
.OwnerWnd
))
4135 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4137 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4139 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4140 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4142 co_UserDestroyWindow(pwndTM
);
4143 mt
.TopMenu
->hWnd
= NULL
;
4145 if (!(wFlags
& TPM_NONOTIFY
))
4147 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4148 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4151 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4152 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4155 /* Reset the variable for hiding menu */
4156 mt
.TopMenu
->TimeToHide
= FALSE
;
4159 /* The return value is only used by TrackPopupMenu */
4160 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4161 if (executedMenuId
== -1) executedMenuId
= 0;
4162 return executedMenuId
;
4165 /***********************************************************************
4168 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4171 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4173 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4175 co_UserHideCaret(0);
4177 /* This makes the menus of applications built with Delphi work.
4178 * It also enables menus to be displayed in more than one window,
4179 * but there are some bugs left that need to be fixed in this case.
4183 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4187 top_popup
= Menu
->hWnd
;
4188 top_popup_hmenu
= UserHMGetHandle(Menu
);
4191 fInsideMenuLoop
= TRUE
;
4194 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4195 if (!(wFlags
& TPM_NONOTIFY
))
4197 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4201 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4203 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4204 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4205 co_UserSetCapture(capture_win
); // 2
4206 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4208 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4210 if (!(wFlags
& TPM_NONOTIFY
))
4212 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4213 /* If an app changed/recreated menu bar entries in WM_INITMENU
4214 * menu sizes will be recalculated once the menu created/shown.
4218 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4220 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4225 /***********************************************************************
4228 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4230 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4232 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4234 if (!(wFlags
& TPM_NONOTIFY
))
4235 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4237 co_UserShowCaret(0);
4240 top_popup_hmenu
= NULL
;
4245 /***********************************************************************
4246 * MenuTrackMouseMenuBar
4248 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4250 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4252 PMENU pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4253 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4255 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4257 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4258 if (VerifyMenu(pMenu
))
4260 /* map point to parent client coordinates */
4261 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4262 if (Parent
!= UserGetDesktopWindow())
4264 IntScreenToClient(Parent
, &pt
);
4267 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4268 /* fetch the window menu again, it may have changed */
4269 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4270 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4271 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4275 /***********************************************************************
4276 * MenuTrackKbdMenuBar
4278 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4280 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4282 UINT uItem
= NO_SELECTED_ITEM
;
4284 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4286 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4288 /* find window that has a menu */
4290 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4291 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4293 /* check if we have to track a system menu */
4295 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4296 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4298 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4299 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4301 wParam
|= HTSYSMENU
; /* prevent item lookup */
4304 if (!VerifyMenu( TrackMenu
)) return;
4306 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4308 /* fetch the window menu again, it may have changed */
4309 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4311 if( wChar
&& wChar
!= ' ' )
4313 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4314 if ( uItem
>= (UINT
)(-2) )
4316 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4317 /* schedule end of menu tracking */
4318 wFlags
|= TF_ENDMENU
;
4323 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4325 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4327 if( uItem
== NO_SELECTED_ITEM
)
4328 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4330 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4334 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4335 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4338 /**********************************************************************
4339 * TrackPopupMenuEx (USER32.@)
4341 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4342 PWND pWnd
, LPTPMPARAMS lpTpm
)
4345 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4347 if (pti
!= pWnd
->head
.pti
)
4349 ERR("Must be the same pti!\n");
4353 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4354 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4355 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4357 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4359 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4363 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4365 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4367 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4368 if (!(wFlags
& TPM_NONOTIFY
))
4370 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4373 if (menu
->fFlags
& MNF_SYSMENU
)
4374 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4376 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4377 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4378 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4381 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4382 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4383 co_UserSetCapture(NULL
); /* release the capture */
4387 // HACK : Until back trace fault in co_IntUpdateWindows and MENU_TrackMenu.
4389 if (EngGetLastError() == ERROR_ACCESS_DENIED
)
4391 EngSetLastError(NO_ERROR
);
4394 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4398 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4399 if (pwndM
) // wine hack around this with their destroy function.
4400 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4403 if (!(wFlags
& TPM_NONOTIFY
))
4405 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4406 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4424 PPOPUPMENU pPopupMenu
;
4428 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4434 if (Message
!= WM_NCCREATE
)
4436 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4439 Wnd
->fnid
= FNID_MENU
;
4440 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4441 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4442 pPopupMenu
->spwndPopupMenu
= Wnd
;
4443 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4444 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4450 if (Wnd
->fnid
!= FNID_MENU
)
4452 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4455 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4463 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4464 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4468 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4469 *lResult
= MA_NOACTIVATE
;
4475 IntBeginPaint(Wnd
, &ps
);
4476 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4477 IntEndPaint(Wnd
, &ps
);
4481 case WM_PRINTCLIENT
:
4483 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4492 /* zero out global pointer in case resident popup window was destroyed. */
4495 if (UserHMGetHandle(Wnd
) == top_popup
)
4498 top_popup_hmenu
= NULL
;
4503 ERR("No Window Pop Up!\n");
4509 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4510 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4511 Wnd
->fnid
= FNID_DESTROY
;
4515 case MM_SETMENUHANDLE
: // wine'isms
4518 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4521 ERR("Bad Menu Handle\n");
4524 pPopupMenu
->spmenu
= pmenu
;
4528 case MM_GETMENUHANDLE
: // wine'isms
4530 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4534 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4536 ERR("Someone is passing unknown menu messages %d\n",Message
);
4538 TRACE("PMWP to IDWP %d\n",Message
);
4539 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4547 IntHiliteMenuItem(PWND WindowObject
,
4553 UINT uItem
= uItemHilite
;
4555 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4557 if (uHilite
& MF_HILITE
)
4559 MenuItem
->fState
|= MF_HILITE
;
4563 MenuItem
->fState
&= ~MF_HILITE
;
4565 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4566 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4567 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4569 return TRUE
; // Always returns true!!!!
4573 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4577 DWORD dwExStyle
= 0;
4578 BOOLEAN retValue
= TRUE
;
4580 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4582 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4584 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4586 dwStyle
= pWindowObject
->style
;
4587 dwExStyle
= pWindowObject
->ExStyle
;
4589 bti
->rcTitleBar
.top
= 0;
4590 bti
->rcTitleBar
.left
= 0;
4591 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4592 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4594 /* Is it iconiced ? */
4595 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4597 /* Remove frame from rectangle */
4598 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4600 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4601 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4603 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4605 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4606 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4608 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4610 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4611 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4614 /* We have additional border information if the window
4615 * is a child (but not an MDI child) */
4616 if ( (dwStyle
& WS_CHILD
) &&
4617 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4619 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4621 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4622 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4625 if (dwExStyle
& WS_EX_STATICEDGE
)
4627 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4628 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4633 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4634 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4635 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4637 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4638 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4640 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4641 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4645 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4646 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4647 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4650 if (dwStyle
& WS_CAPTION
)
4652 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4653 if (dwStyle
& WS_SYSMENU
)
4655 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4657 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4658 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4662 if (!(dwStyle
& WS_MINIMIZEBOX
))
4664 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4666 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4668 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4672 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4674 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4676 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4678 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4683 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4684 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4685 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4686 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4691 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4696 EngSetLastError(ERROR_INVALID_PARAMETER
);
4708 LPCMENUITEMINFOW UnsafeItemInfo
,
4709 PUNICODE_STRING lpstr
)
4712 ROSMENUITEMINFO ItemInfo
;
4714 /* Try to copy the whole MENUITEMINFOW structure */
4715 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4716 if (NT_SUCCESS(Status
))
4718 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4719 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4721 EngSetLastError(ERROR_INVALID_PARAMETER
);
4724 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4727 /* Try to copy without last field (not present in older versions) */
4728 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4729 if (NT_SUCCESS(Status
))
4731 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4733 EngSetLastError(ERROR_INVALID_PARAMETER
);
4736 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4737 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4740 SetLastNtError(Status
);
4744 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4749 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4754 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4756 if (pItem
->spSubMenu
)
4758 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4761 return (pItem
->fType
| pItem
->fState
);
4764 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4769 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4774 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4776 if (pItem
->spSubMenu
)
4778 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4784 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4786 PMENU menu
, pSubTarget
;
4788 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4789 return NO_SELECTED_ITEM
;
4791 pSubTarget
= UserGetMenuObject(hSubTarget
);
4793 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4795 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4801 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4803 PWINSTATION_OBJECT WinStaObject
;
4807 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4809 if (gpepCSRSS
!= CurrentProcess
)
4812 * gpepCSRSS does not have a Win32WindowStation
4815 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4821 if (!NT_SUCCESS(Status
))
4823 ERR("Validation of window station handle (%p) failed\n",
4824 CurrentProcess
->Win32WindowStation
);
4825 SetLastNtError(Status
);
4828 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4829 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4831 ERR("Desktop Window Station does not match Process one!\n");
4833 ObDereferenceObject(WinStaObject
);
4837 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4840 if (Menu
) UserDereferenceObject(Menu
);
4841 return (HMENU
)Handle
;
4849 PROSMENUITEMINFO ItemInfo
,
4851 PUNICODE_STRING lpstr
)
4856 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4858 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4863 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4867 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4877 PROSMENUITEMINFO UnsafeItemInfo
,
4879 PUNICODE_STRING lpstr
)
4882 ROSMENUITEMINFO ItemInfo
;
4887 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4888 if (! NT_SUCCESS(Status
))
4890 SetLastNtError(Status
);
4893 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4894 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4895 Size
!= sizeof(ROSMENUITEMINFO
) )
4897 EngSetLastError(ERROR_INVALID_PARAMETER
);
4900 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4901 if (! NT_SUCCESS(Status
))
4903 SetLastNtError(Status
);
4906 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4908 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4909 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4911 EngSetLastError(ERROR_INVALID_PARAMETER
);
4915 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4917 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4918 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4921 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4927 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4931 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4934 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4935 if (! NT_SUCCESS(Status
))
4937 SetLastNtError(Status
);
4949 PROSMENUINFO UnsafeMenuInfo
,
4955 ROSMENUINFO MenuInfo
;
4957 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4958 if (! NT_SUCCESS(Status
))
4960 SetLastNtError(Status
);
4963 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4965 EngSetLastError(ERROR_INVALID_PARAMETER
);
4968 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4969 if (! NT_SUCCESS(Status
))
4971 SetLastNtError(Status
);
4978 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4983 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4986 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
4987 if (! NT_SUCCESS(Status
))
4989 SetLastNtError(Status
);
5009 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5011 Rect
->left
= MenuItem
->xItem
;
5012 Rect
->top
= MenuItem
->yItem
;
5013 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5014 Rect
->bottom
= MenuItem
->cyItem
;
5018 ERR("Failed Item Lookup! %u\n", uItem
);
5024 HWND hWnd
= Menu
->hWnd
;
5025 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5028 if (Menu
->fFlags
& MNF_POPUP
)
5030 XMove
= pWnd
->rcClient
.left
;
5031 YMove
= pWnd
->rcClient
.top
;
5035 XMove
= pWnd
->rcWindow
.left
;
5036 YMove
= pWnd
->rcWindow
.top
;
5039 Rect
->left
+= XMove
;
5041 Rect
->right
+= XMove
;
5042 Rect
->bottom
+= YMove
;
5047 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5049 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5050 HMENU hSysMenu
, hNewMenu
= NULL
;
5051 ROSMENUITEMINFO ItemInfoSet
= {0};
5052 ROSMENUITEMINFO ItemInfo
= {0};
5053 UNICODE_STRING MenuName
;
5055 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5056 if (NULL
== hSysMenu
)
5060 SysMenu
= UserGetMenuObject(hSysMenu
);
5061 if (NULL
== SysMenu
)
5063 UserDestroyMenu(hSysMenu
);
5067 SysMenu
->fFlags
|= MNF_SYSMENU
;
5068 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5072 //hNewMenu = co_IntLoadSysMenuTemplate();
5073 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5075 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5076 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5080 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5081 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5082 //ERR("%wZ\n",&MenuName);
5087 IntReleaseMenuObject(SysMenu
);
5088 UserDestroyMenu(hSysMenu
);
5091 Menu
= UserGetMenuObject(hNewMenu
);
5094 IntReleaseMenuObject(SysMenu
);
5095 UserDestroyMenu(hSysMenu
);
5099 // Do the rest in here.
5101 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5103 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5104 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5105 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5106 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5107 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5108 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5109 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5110 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5111 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5112 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5114 NewMenu
= IntCloneMenu(Menu
);
5116 IntReleaseMenuObject(NewMenu
);
5117 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5119 IntDestroyMenuObject(Menu
, FALSE
);
5127 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5129 if (Window
->pcls
->style
& CS_NOCLOSE
)
5130 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5132 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5133 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5134 ItemInfo
.fType
= MF_POPUP
;
5135 ItemInfo
.fState
= MFS_ENABLED
;
5136 ItemInfo
.dwTypeData
= NULL
;
5138 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5139 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5143 ERR("failed to load system menu!\n");
5148 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5154 if (Window
->SystemMenu
)
5156 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5157 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5159 IntDestroyMenuObject(Menu
, TRUE
);
5160 Window
->SystemMenu
= NULL
;
5166 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5167 if ((!Window
->SystemMenu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5169 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5170 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5174 if (Window
->SystemMenu
)
5176 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5177 /* Store the dummy sysmenu handle to facilitate the refresh */
5178 /* of the close button if the SC_CLOSE item change */
5179 Menu
= UserGetMenuObject(hMenu
);
5182 Menu
->spwndNotify
= Window
;
5183 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5191 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5195 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5197 if (Window
->SystemMenu
)
5199 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5202 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5203 IntDestroyMenuObject(OldMenu
, TRUE
);
5207 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5209 { // Use spmenuSys too!
5210 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5213 Window
->SystemMenu
= NULL
;
5215 if (Menu
&& Window
!= Menu
->spwndNotify
)
5217 Menu
->spwndNotify
= Window
;
5229 PMENU OldMenu
, NewMenu
= NULL
;
5231 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5233 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5234 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5238 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5246 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5247 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5256 NewMenu
= IntGetMenuObject(Menu
);
5257 if (NULL
== NewMenu
)
5259 if (NULL
!= OldMenu
)
5261 IntReleaseMenuObject(OldMenu
);
5263 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5266 if (NULL
!= NewMenu
->hWnd
)
5268 /* Can't use the same menu for two windows */
5269 if (NULL
!= OldMenu
)
5271 IntReleaseMenuObject(OldMenu
);
5273 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5279 Wnd
->IDMenu
= (UINT
) Menu
;
5280 if (NULL
!= NewMenu
)
5282 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5283 IntReleaseMenuObject(NewMenu
);
5285 if (NULL
!= OldMenu
)
5287 OldMenu
->hWnd
= NULL
;
5288 IntReleaseMenuObject(OldMenu
);
5295 /* FUNCTIONS *****************************************************************/
5301 NtUserCheckMenuItem(
5307 DECLARE_RETURN(DWORD
);
5309 TRACE("Enter NtUserCheckMenuItem\n");
5310 UserEnterExclusive();
5312 if(!(Menu
= UserGetMenuObject(hMenu
)))
5317 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5320 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5335 DECLARE_RETURN(BOOL
);
5337 TRACE("Enter NtUserDeleteMenu\n");
5338 UserEnterExclusive();
5340 if(!(Menu
= UserGetMenuObject(hMenu
)))
5345 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5348 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5354 * NtUserGetSystemMenu
5356 * The NtUserGetSystemMenu function allows the application to access the
5357 * window menu (also known as the system menu or the control menu) for
5358 * copying and modifying.
5362 * Handle to the window that will own a copy of the window menu.
5364 * Specifies the action to be taken. If this parameter is FALSE,
5365 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5366 * currently in use. The copy is initially identical to the window menu
5367 * but it can be modified.
5368 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5369 * to the default state. The previous window menu, if any, is destroyed.
5372 * If the bRevert parameter is FALSE, the return value is a handle to a
5373 * copy of the window menu. If the bRevert parameter is TRUE, the return
5381 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5385 DECLARE_RETURN(HMENU
);
5387 TRACE("Enter NtUserGetSystemMenu\n");
5390 if (!(Window
= UserGetWindowObject(hWnd
)))
5395 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5400 RETURN(Menu
->head
.h
);
5403 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5409 * NtUserSetSystemMenu
5416 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5418 BOOL Result
= FALSE
;
5421 DECLARE_RETURN(BOOL
);
5423 TRACE("Enter NtUserSetSystemMenu\n");
5424 UserEnterExclusive();
5426 if (!(Window
= UserGetWindowObject(hWnd
)))
5434 * Assign new menu handle and Up the Lock Count.
5436 if (!(Menu
= IntGetMenuObject(hMenu
)))
5441 Result
= IntSetSystemMenu(Window
, Menu
);
5444 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5449 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5458 NtUserGetTitleBarInfo(
5463 TITLEBARINFO bartitleinfo
;
5464 DECLARE_RETURN(BOOLEAN
);
5465 BOOLEAN retValue
= TRUE
;
5467 TRACE("Enter NtUserGetTitleBarInfo\n");
5468 UserEnterExclusive();
5470 /* Vaildate the windows handle */
5471 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5473 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5479 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5480 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5481 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5485 /* Fail copy the data */
5486 EngSetLastError(ERROR_INVALID_PARAMETER
);
5491 /* Get the tile bar info */
5494 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5499 /* Copy our buffer to user mode buffer bti */
5500 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5501 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5503 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5505 /* Fail copy the data */
5506 EngSetLastError(ERROR_INVALID_PARAMETER
);
5516 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5524 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5527 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5529 if(!(Menu
= UserGetMenuObject(hMenu
)))
5534 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5536 EngSetLastError(ERROR_ACCESS_DENIED
);
5539 return IntDestroyMenuObject(Menu
, FALSE
);
5550 DECLARE_RETURN(BOOL
);
5552 TRACE("Enter NtUserDestroyMenu\n");
5553 UserEnterExclusive();
5555 if(!(Menu
= UserGetMenuObject(hMenu
)))
5559 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5561 EngSetLastError(ERROR_ACCESS_DENIED
);
5564 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5567 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5576 NtUserEnableMenuItem(
5582 DECLARE_RETURN(UINT
);
5584 TRACE("Enter NtUserEnableMenuItem\n");
5585 UserEnterExclusive();
5587 if(!(Menu
= UserGetMenuObject(hMenu
)))
5592 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5595 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5607 TRACE("Enter NtUserEndMenu\n");
5608 UserEnterExclusive();
5609 /* if ( gptiCurrent->pMenuState &&
5610 gptiCurrent->pMenuState->pGlobalPopupMenu )
5612 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5615 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5618 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5620 if (fInsideMenuLoop
&& top_popup
)
5622 fInsideMenuLoop
= FALSE
;
5623 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5626 TRACE("Leave NtUserEndMenu\n");
5634 NtUserGetMenuBarInfo(
5644 PPOPUPMENU pPopupMenu
;
5645 USER_REFERENCE_ENTRY Ref
;
5646 NTSTATUS Status
= STATUS_SUCCESS
;
5648 DECLARE_RETURN(BOOL
);
5650 TRACE("Enter NtUserGetMenuBarInfo\n");
5653 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5655 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5659 UserRefObjectCo(pWnd
, &Ref
);
5661 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5663 kmbi
.hwndMenu
= NULL
;
5664 kmbi
.fBarFocused
= FALSE
;
5665 kmbi
.fFocused
= FALSE
;
5670 if (!pWnd
->pcls
->fnid
)
5672 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5674 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5675 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5678 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5679 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5680 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5681 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5683 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5685 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5690 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5691 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5692 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5695 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5696 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5697 hMenu
= UserHMGetHandle(Menu
);
5708 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5709 kmbi
.cbSize
= pmbi
->cbSize
;
5711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5717 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5719 EngSetLastError(ERROR_INVALID_PARAMETER
);
5723 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5727 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5732 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5733 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5734 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5735 TRACE("idItem a 0 %d\n",Ret
);
5739 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5740 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5744 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5745 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5748 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5749 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5751 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5756 kmbi
.fFocused
= kmbi
.fBarFocused
;
5761 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5762 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5764 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5766 Status
= _SEH2_GetExceptionCode();
5770 if (!NT_SUCCESS(Status
))
5772 SetLastNtError(Status
);
5779 if (pWnd
) UserDerefObjectCo(pWnd
);
5780 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5793 PMENU Menu
, SubMenu
;
5796 DECLARE_RETURN(UINT
);
5798 TRACE("Enter NtUserGetMenuIndex\n");
5801 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5802 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5805 MenuItem
= Menu
->rgItems
;
5806 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5808 if (MenuItem
->spSubMenu
== SubMenu
)
5809 RETURN(MenuItem
->wID
);
5814 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5823 NtUserGetMenuItemRect(
5834 NTSTATUS Status
= STATUS_SUCCESS
;
5835 DECLARE_RETURN(BOOL
);
5837 TRACE("Enter NtUserGetMenuItemRect\n");
5840 if (!(Menu
= UserGetMenuObject(hMenu
)))
5845 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5847 Rect
.left
= MenuItem
->xItem
;
5848 Rect
.top
= MenuItem
->yItem
;
5849 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5850 Rect
.bottom
= MenuItem
->cyItem
;
5860 if (lprcItem
== NULL
) RETURN( FALSE
);
5862 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5864 if (Menu
->fFlags
& MNF_POPUP
)
5866 XMove
= ReferenceWnd
->rcClient
.left
;
5867 YMove
= ReferenceWnd
->rcClient
.top
;
5871 XMove
= ReferenceWnd
->rcWindow
.left
;
5872 YMove
= ReferenceWnd
->rcWindow
.top
;
5877 Rect
.right
+= XMove
;
5878 Rect
.bottom
+= YMove
;
5882 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5884 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5886 Status
= _SEH2_GetExceptionCode();
5890 if (!NT_SUCCESS(Status
))
5892 SetLastNtError(Status
);
5898 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5907 NtUserHiliteMenuItem(
5915 DECLARE_RETURN(BOOLEAN
);
5917 TRACE("Enter NtUserHiliteMenuItem\n");
5918 UserEnterExclusive();
5920 if(!(Window
= UserGetWindowObject(hWnd
)))
5922 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5926 if(!(Menu
= UserGetMenuObject(hMenu
)))
5928 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5932 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
5935 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
5945 NtUserDrawMenuBarTemp(
5955 NTSTATUS Status
= STATUS_SUCCESS
;
5956 DECLARE_RETURN(DWORD
);
5958 ERR("Enter NtUserDrawMenuBarTemp\n");
5959 UserEnterExclusive();
5961 if(!(Window
= UserGetWindowObject(hWnd
)))
5963 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5967 if(!(Menu
= UserGetMenuObject(hMenu
)))
5969 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5975 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
5976 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
5978 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5980 Status
= _SEH2_GetExceptionCode();
5984 if (Status
!= STATUS_SUCCESS
)
5986 SetLastNtError(Status
);
5990 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
5993 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6002 NtUserMenuItemFromPoint(
6012 DECLARE_RETURN(int);
6014 TRACE("Enter NtUserMenuItemFromPoint\n");
6015 UserEnterExclusive();
6017 if (!(Menu
= UserGetMenuObject(hMenu
)))
6022 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6027 X
-= Window
->rcWindow
.left
;
6028 Y
-= Window
->rcWindow
.top
;
6031 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6035 Rect
.left
= mi
->xItem
;
6036 Rect
.top
= mi
->yItem
;
6037 Rect
.right
= mi
->cxItem
;
6038 Rect
.bottom
= mi
->cyItem
;
6040 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6042 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6048 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6051 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6067 DECLARE_RETURN(BOOL
);
6069 TRACE("Enter NtUserRemoveMenu\n");
6070 UserEnterExclusive();
6072 if(!(Menu
= UserGetMenuObject(hMenu
)))
6077 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6080 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6097 DECLARE_RETURN(BOOL
);
6099 TRACE("Enter NtUserSetMenu\n");
6100 UserEnterExclusive();
6102 if (!(Window
= UserGetWindowObject(hWnd
)))
6107 if (!IntSetMenu(Window
, Menu
, &Changed
))
6112 // Not minimized and please repaint!!!
6113 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6115 USER_REFERENCE_ENTRY Ref
;
6116 UserRefObjectCo(Window
, &Ref
);
6117 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6118 UserDerefObjectCo(Window
);
6124 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6133 NtUserSetMenuContextHelpId(
6135 DWORD dwContextHelpId
)
6138 DECLARE_RETURN(BOOL
);
6140 TRACE("Enter NtUserSetMenuContextHelpId\n");
6141 UserEnterExclusive();
6143 if(!(Menu
= UserGetMenuObject(hMenu
)))
6148 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6151 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6160 NtUserSetMenuDefaultItem(
6166 DECLARE_RETURN(BOOL
);
6168 TRACE("Enter NtUserSetMenuDefaultItem\n");
6169 UserEnterExclusive();
6171 if(!(Menu
= UserGetMenuObject(hMenu
)))
6176 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6179 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6188 NtUserSetMenuFlagRtoL(
6192 DECLARE_RETURN(BOOL
);
6194 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6195 UserEnterExclusive();
6197 if(!(Menu
= UserGetMenuObject(hMenu
)))
6202 RETURN(IntSetMenuFlagRtoL(Menu
));
6205 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6214 NtUserThunkedMenuInfo(
6219 DECLARE_RETURN(BOOL
);
6221 TRACE("Enter NtUserThunkedMenuInfo\n");
6222 UserEnterExclusive();
6224 if (!(Menu
= UserGetMenuObject(hMenu
)))
6229 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6232 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6241 NtUserThunkedMenuItemInfo(
6246 LPMENUITEMINFOW lpmii
,
6247 PUNICODE_STRING lpszCaption
)
6251 UNICODE_STRING lstrCaption
;
6252 DECLARE_RETURN(BOOL
);
6254 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6255 UserEnterExclusive();
6257 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6258 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6260 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6262 if (!(Menu
= UserGetMenuObject(hMenu
)))
6267 /* Check if we got a Caption */
6268 if (lpszCaption
&& lpszCaption
->Buffer
)
6270 /* Copy the string to kernel mode */
6271 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6274 if (!NT_SUCCESS(Status
))
6276 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6277 SetLastNtError(Status
);
6282 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6284 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6287 if (lstrCaption
.Buffer
)
6289 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6292 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6301 NtUserTrackPopupMenuEx(
6313 USER_REFERENCE_ENTRY Ref
;
6315 TRACE("Enter NtUserTrackPopupMenuEx\n");
6316 UserEnterExclusive();
6317 /* Parameter check */
6318 if (!(menu
= UserGetMenuObject( hMenu
)))
6320 ERR("TPME : Invalid Menu handle.\n");
6321 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6325 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6327 ERR("TPME : Invalid Window handle.\n");
6335 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6338 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6340 _SEH2_YIELD(goto Exit
);
6344 UserRefObjectCo(pWnd
, &Ref
);
6345 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6346 UserDerefObjectCo(pWnd
);
6349 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);