2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: win32ss/user/ntuser/menu.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
10 DBG_DEFAULT_CHANNEL(UserMenu
);
12 /* INTERNAL ******************************************************************/
14 HFONT ghMenuFont
= NULL
;
15 HFONT ghMenuFontBold
= NULL
;
16 static SIZE MenuCharSize
;
18 /* Use global popup window because there's no way 2 menus can
19 * be tracked at the same time. */
20 static HWND top_popup
= NULL
;
21 static HMENU top_popup_hmenu
= NULL
;
23 BOOL fInsideMenuLoop
= FALSE
;
24 BOOL fInEndMenu
= FALSE
;
26 /* internal popup menu window messages */
28 #define MM_SETMENUHANDLE (WM_USER + 0)
29 #define MM_GETMENUHANDLE (WM_USER + 1)
31 /* internal flags for menu tracking */
33 #define TF_ENDMENU 0x10000
34 #define TF_SUSPENDPOPUP 0x20000
35 #define TF_SKIPREMOVE 0x40000
38 /* maximum allowed depth of any branch in the menu tree.
39 * This value is slightly larger than in windows (25) to
40 * stay on the safe side. */
41 #define MAXMENUDEPTH 30
43 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
45 #define MENUITEMINFO_TYPE_MASK \
46 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
47 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
48 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
50 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
52 #define STATE_MASK (~TYPE_MASK)
54 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
56 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
58 #define IS_SYSTEM_MENU(MenuInfo) \
59 (!((MenuInfo)->fFlags & MNF_POPUP) && ((MenuInfo)->fFlags & MNF_SYSMENU))
61 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
63 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
64 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
66 /* Maximum number of menu items a menu can contain */
67 #define MAX_MENU_ITEMS (0x4000)
68 #define MAX_GOINTOSUBMENU (0x10)
70 /* Space between 2 columns */
71 #define MENU_COL_SPACE 4
73 /* top and bottom margins for popup menus */
74 #define MENU_TOP_MARGIN 2 //3
75 #define MENU_BOTTOM_MARGIN 2
77 #define MENU_ITEM_HBMP_SPACE (5)
78 #define MENU_BAR_ITEMS_SPACE (12)
79 #define SEPARATOR_HEIGHT (5)
80 #define MENU_TAB_SPACE (8)
85 PMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
86 PMENU TopMenu
; /* initial menu */
87 PWND OwnerWnd
; /* where notifications are sent */
91 /* Internal MenuTrackMenu() flags */
92 #define TPM_INTERNAL 0xF0000000
93 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
94 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
99 #define UpdateMenuItemState(state, change) \
101 if((change) & MF_GRAYED) { \
102 (state) |= MF_GRAYED; \
104 (state) &= ~MF_GRAYED; \
105 } /* Separate the two for test_menu_resource_layout.*/ \
106 if((change) & MF_DISABLED) { \
107 (state) |= MF_DISABLED; \
109 (state) &= ~MF_DISABLED; \
111 if((change) & MFS_CHECKED) { \
112 (state) |= MFS_CHECKED; \
114 (state) &= ~MFS_CHECKED; \
116 if((change) & MFS_HILITE) { \
117 (state) |= MFS_HILITE; \
119 (state) &= ~MFS_HILITE; \
121 if((change) & MFS_DEFAULT) { \
122 (state) |= MFS_DEFAULT; \
124 (state) &= ~MFS_DEFAULT; \
126 if((change) & MF_MOUSESELECT) { \
127 (state) |= MF_MOUSESELECT; \
129 (state) &= ~MF_MOUSESELECT; \
135 DumpMenuItemList(PMENU Menu
, PITEM MenuItem
)
137 UINT cnt
= 0, i
= Menu
->cItems
;
140 if(MenuItem
->lpstr
.Length
)
141 DbgPrint(" %d. %wZ\n", ++cnt
, &MenuItem
->lpstr
);
143 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt
, (DWORD
)MenuItem
->lpstr
.Buffer
);
145 if(MFT_BITMAP
& MenuItem
->fType
)
146 DbgPrint("MFT_BITMAP ");
147 if(MFT_MENUBARBREAK
& MenuItem
->fType
)
148 DbgPrint("MFT_MENUBARBREAK ");
149 if(MFT_MENUBREAK
& MenuItem
->fType
)
150 DbgPrint("MFT_MENUBREAK ");
151 if(MFT_OWNERDRAW
& MenuItem
->fType
)
152 DbgPrint("MFT_OWNERDRAW ");
153 if(MFT_RADIOCHECK
& MenuItem
->fType
)
154 DbgPrint("MFT_RADIOCHECK ");
155 if(MFT_RIGHTJUSTIFY
& MenuItem
->fType
)
156 DbgPrint("MFT_RIGHTJUSTIFY ");
157 if(MFT_SEPARATOR
& MenuItem
->fType
)
158 DbgPrint("MFT_SEPARATOR ");
159 if(MFT_STRING
& MenuItem
->fType
)
160 DbgPrint("MFT_STRING ");
161 DbgPrint("\n fState=");
162 if(MFS_DISABLED
& MenuItem
->fState
)
163 DbgPrint("MFS_DISABLED ");
165 DbgPrint("MFS_ENABLED ");
166 if(MFS_CHECKED
& MenuItem
->fState
)
167 DbgPrint("MFS_CHECKED ");
169 DbgPrint("MFS_UNCHECKED ");
170 if(MFS_HILITE
& MenuItem
->fState
)
171 DbgPrint("MFS_HILITE ");
173 DbgPrint("MFS_UNHILITE ");
174 if(MFS_DEFAULT
& MenuItem
->fState
)
175 DbgPrint("MFS_DEFAULT ");
176 if(MFS_GRAYED
& MenuItem
->fState
)
177 DbgPrint("MFS_GRAYED ");
178 DbgPrint("\n wId=%d\n", MenuItem
->wID
);
182 DbgPrint("Entries: %d\n", cnt
);
187 #define FreeMenuText(Menu,MenuItem) \
189 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
190 (MenuItem)->lpstr.Length) { \
191 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
196 IntGetMenuObject(HMENU hMenu
)
198 PMENU Menu
= UserGetMenuObject(hMenu
);
200 Menu
->head
.cLockObj
++;
205 PMENU FASTCALL
VerifyMenu(PMENU pMenu
)
211 if (!pMenu
) return NULL
;
213 Error
= EngGetLastError();
217 hMenu
= UserHMGetHandle(pMenu
);
218 pItem
= pMenu
->rgItems
;
225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
227 ERR("Run away LOOP!\n");
228 EngSetLastError(Error
);
229 _SEH2_YIELD(return NULL
);
233 if ( UserObjectInDestroy(hMenu
))
235 ERR("Menu is marked for destruction!\n");
238 EngSetLastError(Error
);
244 IntIsMenu(HMENU Menu
)
246 if (UserGetMenuObject(Menu
)) return TRUE
;
252 IntGetMenu(HWND hWnd
)
254 PWND Wnd
= ValidateHwndNoErr(hWnd
);
259 return UserGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
262 PMENU
get_win_sys_menu( HWND hwnd
)
265 WND
*win
= ValidateHwndNoErr( hwnd
);
268 ret
= UserGetMenuObject(win
->SystemMenu
);
273 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
)
277 if (pMenu
->rgItems
) /* recursively destroy submenus */
280 ITEM
*item
= pMenu
->rgItems
;
281 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
283 SubMenu
= item
->spSubMenu
;
284 item
->spSubMenu
= NULL
;
286 /* Remove Item Text */
287 FreeMenuText(pMenu
,item
);
289 /* Remove Item Bitmap and set it for this process */
290 if (item
->hbmp
&& !(item
->fState
& MFS_HBMMENUBMP
))
292 GreSetObjectOwner(item
->hbmp
, GDI_OBJ_HMGR_POWNED
);
296 /* Remove Item submenu */
297 if (bRecurse
&& SubMenu
)//VerifyMenu(SubMenu))
299 /* Release submenu since it was referenced when inserted */
300 IntReleaseMenuObject(SubMenu
);
301 IntDestroyMenuObject(SubMenu
, bRecurse
);
305 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
306 pMenu
->rgItems
= NULL
;
312 /* Callback for the object manager */
314 UserDestroyMenuObject(PVOID Object
)
316 return IntDestroyMenuObject(Object
, TRUE
);
320 IntDestroyMenuObject(PMENU Menu
, BOOL bRecurse
)
326 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
331 Window
= ValidateHwndNoErr(Menu
->hWnd
);
334 //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
336 /* DestroyMenu should not destroy system menu popup owner */
337 if ((Menu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
)
339 // Should we check it to see if it has Class?
340 ERR("FIXME Pop up menu window thing'ie\n");
341 //co_UserDestroyWindow( Window );
347 if (!UserMarkObjectDestroy(Menu
)) return TRUE
;
349 /* Remove all menu items */
350 IntDestroyMenu( Menu
, bRecurse
);
352 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
353 TRACE("IntDestroyMenuObject %d\n",ret
);
363 NONCLIENTMETRICSW ncm
;
365 /* get the menu font */
366 if (!ghMenuFont
|| !ghMenuFontBold
)
368 ncm
.cbSize
= sizeof(ncm
);
369 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
371 ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
375 ghMenuFont
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
376 if (ghMenuFont
== NULL
)
378 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
381 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
382 ghMenuFontBold
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
383 if (ghMenuFontBold
== NULL
)
385 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
386 GreDeleteObject(ghMenuFont
);
391 GreSetObjectOwner(ghMenuFont
, GDI_OBJ_HMGR_PUBLIC
);
392 GreSetObjectOwner(ghMenuFontBold
, GDI_OBJ_HMGR_PUBLIC
);
401 /**********************************************************************
404 * detect if there are loops in the menu tree (or the depth is too large)
406 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
412 if (!pmenu
) return depth
;
415 if( depth
> MAXMENUDEPTH
) return depth
;
416 item
= pmenu
->rgItems
;
418 for( i
= 0; i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
420 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
422 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
423 if( bdepth
> subdepth
) subdepth
= bdepth
;
425 if( subdepth
> MAXMENUDEPTH
)
426 TRACE("<- hmenu %p\n", item
->spSubMenu
);
432 /******************************************************************************
434 * UINT MenuGetStartOfNextColumn(
437 *****************************************************************************/
439 static UINT
MENU_GetStartOfNextColumn(
446 return NO_SELECTED_ITEM
;
449 if( i
== NO_SELECTED_ITEM
)
452 pItem
= menu
->rgItems
;
453 if (!pItem
) return NO_SELECTED_ITEM
;
455 for( ; i
< menu
->cItems
; ++i
) {
456 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
460 return NO_SELECTED_ITEM
;
463 /******************************************************************************
465 * UINT MenuGetStartOfPrevColumn(
468 *****************************************************************************/
469 static UINT
MENU_GetStartOfPrevColumn(
476 return NO_SELECTED_ITEM
;
478 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
479 return NO_SELECTED_ITEM
;
481 pItem
= menu
->rgItems
;
482 if (!pItem
) return NO_SELECTED_ITEM
;
484 /* Find the start of the column */
486 for(i
= menu
->iItem
; i
!= 0 &&
487 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
491 return NO_SELECTED_ITEM
;
493 for(--i
; i
!= 0; --i
) {
494 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
498 TRACE("ret %d.\n", i
);
503 /***********************************************************************
506 * Find a menu item. Return a pointer on the item, and modifies *hmenu
507 * in case the item was in a sub-menu.
509 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
512 ITEM
*fallback
= NULL
;
513 UINT fallback_pos
= 0;
516 if (!menu
) return NULL
;
518 if (wFlags
& MF_BYPOSITION
)
520 if (!menu
->cItems
) return NULL
;
521 if (*nPos
>= menu
->cItems
) return NULL
;
522 return &menu
->rgItems
[*nPos
];
526 PITEM item
= menu
->rgItems
;
527 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
531 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
532 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
538 else if (item
->wID
== *nPos
)
540 /* fallback to this item if nothing else found */
545 else if (item
->wID
== *nPos
)
554 *nPos
= fallback_pos
;
559 /***********************************************************************
562 * Find a Sub menu. Return the position of the submenu, and modifies
563 * *hmenu in case it is found in another sub-menu.
564 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
566 static UINT FASTCALL
MENU_FindSubMenu(PMENU
*menu
, PMENU SubTarget
)
571 item
= ((PMENU
)*menu
)->rgItems
;
572 for (i
= 0; i
< ((PMENU
)*menu
)->cItems
; i
++, item
++)
574 if (!item
->spSubMenu
)
578 if (item
->spSubMenu
== SubTarget
)
584 PMENU pSubMenu
= item
->spSubMenu
;
585 UINT pos
= MENU_FindSubMenu( &pSubMenu
, SubTarget
);
586 if (pos
!= NO_SELECTED_ITEM
)
594 return NO_SELECTED_ITEM
;
598 IntRemoveMenuItem( PMENU pMenu
, UINT nPos
, UINT wFlags
, BOOL bRecurse
)
603 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
604 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
608 FreeMenuText(pMenu
,item
);
609 if (bRecurse
&& item
->spSubMenu
)
611 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
);
613 ////// Use cAlloced with inc's of 8's....
614 if (--pMenu
->cItems
== 0)
616 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
617 pMenu
->rgItems
= NULL
;
621 while (nPos
< pMenu
->cItems
)
627 newItems
= DesktopHeapReAlloc(pMenu
->head
.rpdesk
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
630 pMenu
->rgItems
= newItems
;
636 /**********************************************************************
639 * Insert (allocate) a new item into a menu.
641 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
645 /* Find where to insert new item */
647 if (flags
& MF_BYPOSITION
) {
648 if (pos
> menu
->cItems
)
651 if (!MENU_FindItem( &menu
, &pos
, flags
))
653 if (submenu
) *submenu
= menu
;
654 if (npos
) *npos
= pos
;
659 /* Make sure that MDI system buttons stay on the right side.
660 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
661 * regardless of their id.
664 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
665 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
668 TRACE("inserting at %u flags %x\n", pos
, flags
);
670 /* Create new items array */
672 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
675 WARN("allocation failed\n" );
678 if (menu
->cItems
> 0)
680 /* Copy the old array into the new one */
681 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
682 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
683 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
685 menu
->rgItems
= newItems
;
687 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
688 menu
->cyMenu
= 0; /* force size recalculate */
689 return &newItems
[pos
];
694 _In_ PMENU MenuObject
,
697 PROSMENUITEMINFO ItemInfo
,
698 PUNICODE_STRING lpstr
)
701 PMENU SubMenu
= NULL
;
703 NT_ASSERT(MenuObject
!= NULL
);
705 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
707 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
711 SubMenu
= MenuObject
;
713 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
715 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
717 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
721 /* Force size recalculation! */
723 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
725 TRACE("IntInsertMenuItemToList = %u %i\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
732 _Out_ PHANDLE Handle
,
734 _In_ PDESKTOP Desktop
,
735 _In_ PPROCESSINFO ppi
)
739 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
751 Menu
->cyMax
= 0; /* Default */
752 Menu
->hbrBack
= NULL
; /* No brush */
753 Menu
->dwContextHelpId
= 0; /* Default */
754 Menu
->dwMenuData
= 0; /* Default */
755 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
756 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
757 Menu
->spwndNotify
= NULL
;
758 Menu
->cyMenu
= 0; // Height
759 Menu
->cxMenu
= 0; // Width
760 Menu
->cItems
= 0; // Item count
763 Menu
->cxTextAlign
= 0;
764 Menu
->rgItems
= NULL
;
767 Menu
->TimeToHide
= FALSE
;
773 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
775 PITEM MenuItem
, NewMenuItem
= NULL
;
781 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, (Source
->cItems
+1) * sizeof(ITEM
));
782 if(!NewMenuItem
) return FALSE
;
784 RtlZeroMemory(NewMenuItem
, (Source
->cItems
+1) * sizeof(ITEM
));
786 Destination
->rgItems
= NewMenuItem
;
788 MenuItem
= Source
->rgItems
;
789 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
791 NewMenuItem
->fType
= MenuItem
->fType
;
792 NewMenuItem
->fState
= MenuItem
->fState
;
793 NewMenuItem
->wID
= MenuItem
->wID
;
794 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
795 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
796 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
797 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
798 if (MenuItem
->lpstr
.Length
)
800 NewMenuItem
->lpstr
.Length
= 0;
801 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
802 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
803 if (!NewMenuItem
->lpstr
.Buffer
)
805 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
808 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
809 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
810 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
814 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
815 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
817 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
823 IntCloneMenu(PMENU Source
)
831 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
832 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
834 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
841 Menu
->fFlags
= Source
->fFlags
;
842 Menu
->cyMax
= Source
->cyMax
;
843 Menu
->hbrBack
= Source
->hbrBack
;
844 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
845 Menu
->dwMenuData
= Source
->dwMenuData
;
846 Menu
->iItem
= NO_SELECTED_ITEM
;
847 Menu
->spwndNotify
= NULL
;
850 Menu
->cItems
= Source
->cItems
;
853 Menu
->cxTextAlign
= 0;
854 Menu
->rgItems
= NULL
;
857 Menu
->TimeToHide
= FALSE
;
859 IntCloneMenuItems(Menu
, Source
);
865 IntSetMenuFlagRtoL(PMENU Menu
)
867 ERR("SetMenuFlagRtoL\n");
868 Menu
->fFlags
|= MNF_RTOL
;
873 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
875 Menu
->dwContextHelpId
= dwContextHelpId
;
880 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
882 if(lpmi
->fMask
& MIM_BACKGROUND
)
883 lpmi
->hbrBack
= Menu
->hbrBack
;
884 if(lpmi
->fMask
& MIM_HELPID
)
885 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
886 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
887 lpmi
->cyMax
= Menu
->cyMax
;
888 if(lpmi
->fMask
& MIM_MENUDATA
)
889 lpmi
->dwMenuData
= Menu
->dwMenuData
;
890 if(lpmi
->fMask
& MIM_STYLE
)
891 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
893 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
895 lpmi
->cItems
= Menu
->cItems
;
897 lpmi
->iItem
= Menu
->iItem
;
898 lpmi
->cxMenu
= Menu
->cxMenu
;
899 lpmi
->cyMenu
= Menu
->cyMenu
;
900 lpmi
->spwndNotify
= Menu
->spwndNotify
;
901 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
902 lpmi
->iTop
= Menu
->iTop
;
903 lpmi
->iMaxTop
= Menu
->iMaxTop
;
904 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
906 lpmi
->fFlags
= Menu
->fFlags
;
907 lpmi
->Self
= Menu
->head
.h
;
908 lpmi
->TimeToHide
= Menu
->TimeToHide
;
909 lpmi
->Wnd
= Menu
->hWnd
;
915 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
917 if(lpmi
->fMask
& MIM_BACKGROUND
)
918 Menu
->hbrBack
= lpmi
->hbrBack
;
919 if(lpmi
->fMask
& MIM_HELPID
)
920 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
921 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
922 Menu
->cyMax
= lpmi
->cyMax
;
923 if(lpmi
->fMask
& MIM_MENUDATA
)
924 Menu
->dwMenuData
= lpmi
->dwMenuData
;
925 if(lpmi
->fMask
& MIM_STYLE
)
926 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
927 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
930 PITEM item
= Menu
->rgItems
;
931 for ( i
= Menu
->cItems
; i
; i
--, item
++)
933 if ( item
->spSubMenu
)
935 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
939 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
941 Menu
->iItem
= lpmi
->iItem
;
942 Menu
->cyMenu
= lpmi
->cyMenu
;
943 Menu
->cxMenu
= lpmi
->cxMenu
;
944 Menu
->spwndNotify
= lpmi
->spwndNotify
;
945 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
946 Menu
->iTop
= lpmi
->iTop
;
947 Menu
->iMaxTop
= lpmi
->iMaxTop
;
948 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
950 Menu
->TimeToHide
= lpmi
->TimeToHide
;
951 Menu
->hWnd
= lpmi
->Wnd
;
953 if ( lpmi
->fMask
& MIM_STYLE
)
955 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
956 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
957 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
963 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
964 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
968 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
970 lpmii
->fType
= MenuItem
->fType
;
972 if(lpmii
->fMask
& MIIM_BITMAP
)
974 lpmii
->hbmpItem
= MenuItem
->hbmp
;
976 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
978 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
979 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
981 if(lpmii
->fMask
& MIIM_DATA
)
983 lpmii
->dwItemData
= MenuItem
->dwItemData
;
985 if(lpmii
->fMask
& MIIM_ID
)
987 lpmii
->wID
= MenuItem
->wID
;
989 if(lpmii
->fMask
& MIIM_STATE
)
991 lpmii
->fState
= MenuItem
->fState
;
993 if(lpmii
->fMask
& MIIM_SUBMENU
)
995 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
998 if ((lpmii
->fMask
& MIIM_STRING
) ||
999 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1001 if (lpmii
->dwTypeData
== NULL
)
1003 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1006 { //// lpmii->lpstr can be read in user mode!!!!
1007 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1008 min(lpmii
->cch
* sizeof(WCHAR
),
1009 MenuItem
->lpstr
.MaximumLength
));
1010 if (! NT_SUCCESS(Status
))
1012 SetLastNtError(Status
);
1018 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1020 lpmii
->Rect
.left
= MenuItem
->xItem
;
1021 lpmii
->Rect
.top
= MenuItem
->yItem
;
1022 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1023 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1024 lpmii
->dxTab
= MenuItem
->dxTab
;
1025 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1026 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1027 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1034 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1036 PMENU SubMenuObject
;
1037 BOOL circref
= FALSE
;
1039 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1043 if ( lpmii
->fMask
& MIIM_FTYPE
)
1045 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1046 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1048 if (lpmii
->fMask
& MIIM_TYPE
)
1050 #if 0 //// Done in User32.
1051 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1053 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1054 KeRosDumpStackFrames(NULL
, 20);
1055 /* This does not happen on Win9x/ME */
1056 SetLastNtError( ERROR_INVALID_PARAMETER
);
1061 * Delete the menu item type when changing type from
1064 if (MenuItem
->fType
!= lpmii
->fType
&&
1065 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1067 FreeMenuText(MenuObject
,MenuItem
);
1068 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1069 MenuItem
->Xlpstr
= NULL
;
1071 if(lpmii
->fType
& MFT_BITMAP
)
1074 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1076 { /* Win 9x/Me stuff */
1077 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1079 lpmii
->dwTypeData
= 0;
1082 if(lpmii
->fMask
& MIIM_BITMAP
)
1084 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1085 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1086 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1088 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1090 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1092 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1093 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1095 if(lpmii
->fMask
& MIIM_DATA
)
1097 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1099 if(lpmii
->fMask
& MIIM_ID
)
1101 MenuItem
->wID
= lpmii
->wID
;
1103 if(lpmii
->fMask
& MIIM_STATE
)
1105 /* Remove MFS_DEFAULT flag from all other menu items if this item
1106 has the MFS_DEFAULT state */
1107 if(lpmii
->fState
& MFS_DEFAULT
)
1108 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1109 /* Update the menu item state flags */
1110 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1113 if(lpmii
->fMask
& MIIM_SUBMENU
)
1115 if (lpmii
->hSubMenu
)
1117 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1118 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1120 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1122 if (MenuObject
== SubMenuObject
)
1125 ERR("Pop Up Menu Double Trouble!\n");
1126 SubMenuObject
= IntCreateMenu(&hMenu
,
1128 MenuObject
->head
.rpdesk
,
1129 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1130 if (!SubMenuObject
) return FALSE
;
1131 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1134 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1136 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1137 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1140 /* Make sure the submenu is marked as a popup menu */
1141 SubMenuObject
->fFlags
|= MNF_POPUP
;
1142 // Now fix the test_subpopup_locked_by_menu tests....
1143 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1144 MenuItem
->spSubMenu
= SubMenuObject
;
1145 UserReferenceObject(SubMenuObject
);
1149 EngSetLastError( ERROR_INVALID_PARAMETER
);
1154 { // If submenu just dereference it.
1155 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1156 MenuItem
->spSubMenu
= NULL
;
1160 if ((lpmii
->fMask
& MIIM_STRING
) ||
1161 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1163 /* free the string when used */
1164 FreeMenuText(MenuObject
,MenuItem
);
1165 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1166 MenuItem
->Xlpstr
= NULL
;
1168 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1170 UNICODE_STRING Source
;
1172 Source
.Length
= Source
.MaximumLength
= lpmii
->cch
* sizeof(WCHAR
);
1173 Source
.Buffer
= lpmii
->dwTypeData
;
1175 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1176 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1178 MenuItem
->lpstr
.Length
= 0;
1179 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1180 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1181 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1183 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1184 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1189 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1190 !MenuItem
->Xlpstr
&&
1191 !lpmii
->dwTypeData
&&
1192 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1194 MenuItem
->fType
|= MFT_SEPARATOR
;
1196 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1198 MenuItem
->xItem
= lpmii
->Rect
.left
;
1199 MenuItem
->yItem
= lpmii
->Rect
.top
;
1200 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1201 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1202 MenuItem
->dxTab
= lpmii
->dxTab
;
1203 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1204 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1205 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1213 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1218 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1220 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1222 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1224 /* If the close item in the system menu change update the close button */
1227 switch (MenuItem
->wID
) // More than just close.
1235 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1237 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1239 /* Refresh the frame to reflect the change */
1240 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1242 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1245 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1255 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1260 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1262 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1264 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1270 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1273 PITEM MenuItem
= MenuObject
->rgItems
;
1275 if (!MenuItem
) return FALSE
;
1277 /* reset all default-item flags */
1278 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1280 MenuItem
->fState
&= ~MFS_DEFAULT
;
1283 /* no default item */
1284 if(uItem
== (UINT
)-1)
1288 MenuItem
= MenuObject
->rgItems
;
1291 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1292 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1297 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1299 if (MenuItem
->wID
== uItem
)
1301 MenuItem
->fState
|= MFS_DEFAULT
;
1311 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1314 PITEM MenuItem
= MenuObject
->rgItems
;
1317 if (!MenuItem
) return -1;
1319 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1322 if (i
>= MenuObject
->cItems
) return -1;
1325 /* default: don't return disabled items */
1326 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1328 /* search rekursiv when needed */
1329 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1333 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1335 if ( -1 != ret
) return ret
;
1337 /* when item not found in submenu, return the popup item */
1339 return ( fByPos
) ? i
: MenuItem
->wID
;
1349 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1350 return pItem
->spSubMenu
;
1353 /***********************************************************************
1354 * MenuInitSysMenuPopup
1356 * Grey the appropriate items in System menu.
1358 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1363 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1364 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1365 gray
= ((style
& WS_MAXIMIZE
) != 0);
1366 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1367 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1368 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1369 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1370 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1371 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1372 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1373 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1375 /* The menu item must keep its state if it's disabled */
1377 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1379 /* Set default menu item */
1380 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1381 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1382 else DefItem
= SC_CLOSE
;
1384 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1388 /***********************************************************************
1389 * MenuDrawPopupGlyph
1391 * Draws popup magic glyphs (can be found in system menu).
1393 static void FASTCALL
1394 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1397 HFONT hFont
, hOldFont
;
1403 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1406 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1409 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1412 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1416 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1419 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1420 RECTL_vInflateRect(r
, -2, -2);
1421 lf
.lfHeight
= r
->bottom
- r
->top
;
1423 lf
.lfWeight
= FW_NORMAL
;
1424 lf
.lfCharSet
= DEFAULT_CHARSET
;
1425 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1426 hFont
= GreCreateFontIndirectW(&lf
);
1427 /* save font and text color */
1428 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1429 clrsave
= GreGetTextColor(dc
);
1430 bkmode
= GreGetBkMode(dc
);
1431 /* set color and drawing mode */
1432 IntGdiSetBkMode(dc
, TRANSPARENT
);
1438 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1439 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1442 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1443 /* draw selected symbol */
1444 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1445 /* restore previous settings */
1446 IntGdiSetTextColor(dc
, clrsave
);
1447 NtGdiSelectFont(dc
, hOldFont
);
1448 IntGdiSetBkMode(dc
, bkmode
);
1449 GreDeleteObject(hFont
);
1452 /***********************************************************************
1453 * MENU_AdjustMenuItemRect
1455 * Adjust menu item rectangle according to scrolling state.
1458 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1460 if (menu
->dwArrowsOn
)
1462 UINT arrow_bitmap_height
;
1463 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1464 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1465 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1469 /***********************************************************************
1470 * MENU_FindItemByCoords
1472 * Find the item at the specified coordinates (screen coords). Does
1473 * not work for child windows and therefore should not be called for
1474 * an arbitrary system menu.
1476 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1481 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1483 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1484 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1485 pt
.x
= rect
.right
- 1 - pt
.x
;
1489 item
= menu
->rgItems
;
1490 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1492 //rect = item->rect;
1493 rect
.left
= item
->xItem
;
1494 rect
.top
= item
->yItem
;
1495 rect
.right
= item
->cxItem
; // Do this for now......
1496 rect
.bottom
= item
->cyItem
;
1498 MENU_AdjustMenuItemRect(menu
, &rect
);
1499 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1508 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1510 MENU
*menu
= UserGetMenuObject(hMenu
);
1513 /*FIXME: Do we have to handle hWnd here? */
1514 if (!menu
) return -1;
1515 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1519 /***********************************************************************
1522 * Find the menu item selected by a key press.
1523 * Return item id, -1 if none, -2 if we should close the menu.
1525 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1526 WCHAR Key
, BOOL ForceMenuChar
)
1531 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1533 if (!menu
|| !VerifyMenu(menu
))
1534 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1537 ITEM
*item
= menu
->rgItems
;
1539 if ( !ForceMenuChar
)
1542 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1544 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1546 LPWSTR text
= item
->Xlpstr
;
1549 const WCHAR
*p
= text
- 2;
1552 const WCHAR
*q
= p
+ 2;
1553 p
= wcschr (q
, '&');
1554 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1556 while (p
!= NULL
&& p
[1] == '&');
1557 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1562 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1563 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1565 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1566 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1567 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1568 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1573 /***********************************************************************
1574 * MenuGetBitmapItemSize
1576 * Get the size of a bitmap item.
1578 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1581 HBITMAP bmp
= lpitem
->hbmp
;
1583 size
->cx
= size
->cy
= 0;
1585 /* check if there is a magic menu item associated with this item */
1586 if (IS_MAGIC_BITMAP(bmp
))
1588 switch((INT_PTR
) bmp
)
1590 case (INT_PTR
)HBMMENU_CALLBACK
:
1592 MEASUREITEMSTRUCT measItem
;
1593 measItem
.CtlType
= ODT_MENU
;
1595 measItem
.itemID
= lpitem
->wID
;
1596 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1597 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1598 measItem
.itemData
= lpitem
->dwItemData
;
1599 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1600 size
->cx
= measItem
.itemWidth
;
1601 size
->cy
= measItem
.itemHeight
;
1602 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1607 case (INT_PTR
) HBMMENU_SYSTEM
:
1608 if (lpitem
->dwItemData
)
1610 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1614 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1615 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1616 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1617 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1618 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1619 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1620 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1621 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1622 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1623 /* FIXME: Why we need to subtract these magic values? */
1624 /* to make them smaller than the menu bar? */
1625 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1626 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1631 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1633 size
->cx
= bm
.bmWidth
;
1634 size
->cy
= bm
.bmHeight
;
1638 /***********************************************************************
1639 * MenuDrawBitmapItem
1641 * Draw a bitmap item.
1643 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1644 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1650 int w
= rect
->right
- rect
->left
;
1651 int h
= rect
->bottom
- rect
->top
;
1652 int bmp_xoffset
= 0;
1654 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1657 /* Check if there is a magic menu item associated with this item */
1658 if (IS_MAGIC_BITMAP(hbmToDraw
))
1664 switch ((INT_PTR
)hbmToDraw
)
1666 case (INT_PTR
)HBMMENU_SYSTEM
:
1667 if (lpitem
->dwItemData
)
1669 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1671 ERR("Get Item Data from this Window!!!\n");
1674 ERR("Draw Bitmap\n");
1675 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1676 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1680 PCURICON_OBJECT pIcon
= NULL
;
1681 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1683 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1684 /* only use right half of the bitmap */
1685 //bmp_xoffset = bm.bmWidth / 2;
1686 //bm.bmWidth -= bmp_xoffset;
1689 pIcon
= NC_IconForWindow(WndOwner
);
1690 // FIXME: NC_IconForWindow should reference it for us */
1691 if (pIcon
) UserReferenceObject(pIcon
);
1696 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1697 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1698 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1699 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1700 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1701 UserDereferenceObject(pIcon
);
1706 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1707 flags
= DFCS_CAPTIONRESTORE
;
1709 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1711 flags
= DFCS_CAPTIONMIN
;
1713 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1715 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1717 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1718 flags
= DFCS_CAPTIONCLOSE
;
1720 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1721 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1723 case (INT_PTR
)HBMMENU_CALLBACK
:
1725 DRAWITEMSTRUCT drawItem
;
1727 drawItem
.CtlType
= ODT_MENU
;
1729 drawItem
.itemID
= lpitem
->wID
;
1730 drawItem
.itemAction
= odaction
;
1731 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1732 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1733 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1734 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1735 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1736 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1737 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1738 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1740 drawItem
.rcItem
= *rect
;
1741 drawItem
.itemData
= lpitem
->dwItemData
;
1742 /* some applications make this assumption on the DC's origin */
1743 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1744 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1745 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1746 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1751 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1752 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1753 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1754 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1755 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1758 RECTL_vInflateRect(&r
, -1, -1);
1759 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1760 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1764 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1767 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1768 NtGdiSelectBitmap( hdcMem
, bmp
);
1769 /* handle fontsize > bitmap_height */
1770 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1772 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1773 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1774 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1775 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1776 IntGdiDeleteDC( hdcMem
, FALSE
);
1780 IntGetDialogBaseUnits(VOID
)
1789 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1791 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1792 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1793 UserReleaseDC( 0, hdc
, FALSE
);
1800 /***********************************************************************
1803 * Calculate the size of the menu item and store it in lpitem->rect.
1805 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1806 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1809 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1810 UINT arrow_bitmap_width
;
1814 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1816 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1818 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1820 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1822 if (lpitem
->fType
& MF_OWNERDRAW
)
1824 MEASUREITEMSTRUCT mis
;
1825 mis
.CtlType
= ODT_MENU
;
1827 mis
.itemID
= lpitem
->wID
;
1828 mis
.itemData
= lpitem
->dwItemData
;
1829 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1831 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1832 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1833 * width of a menufont character to the width of an owner-drawn menu.
1835 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1837 /* under at least win95 you seem to be given a standard
1838 height for the menu and the height value is ignored */
1839 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1841 Rect
.bottom
+= mis
.itemHeight
;
1843 //lpitem->cxBmp = mis.itemWidth;
1844 //lpitem->cyBmp = mis.itemHeight;
1845 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1846 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1847 lpitem
->wID
, Rect
.right
-Rect
.left
,
1848 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1850 lpitem
->xItem
= Rect
.left
;
1851 lpitem
->yItem
= Rect
.top
;
1852 lpitem
->cxItem
= Rect
.right
;
1853 lpitem
->cyItem
= Rect
.bottom
;
1858 lpitem
->xItem
= orgX
;
1859 lpitem
->yItem
= orgY
;
1860 lpitem
->cxItem
= orgX
;
1861 lpitem
->cyItem
= orgY
;
1863 if (lpitem
->fType
& MF_SEPARATOR
)
1865 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1867 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1878 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1879 /* Keep the size of the bitmap in callback mode to be able
1880 * to draw it correctly */
1881 lpitem
->cxBmp
= size
.cx
;
1882 lpitem
->cyBmp
= size
.cy
;
1883 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1884 lpitem
->cxItem
+= size
.cx
+ 2;
1885 itemheight
= size
.cy
+ 2;
1887 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1888 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1889 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1890 lpitem
->dxTab
= lpitem
->cxItem
;
1891 lpitem
->cxItem
+= arrow_bitmap_width
;
1892 } else /* hbmpItem & MenuBar */ {
1893 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1894 lpitem
->cxItem
+= size
.cx
;
1895 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1896 itemheight
= size
.cy
;
1898 /* Special case: Minimize button doesn't have a space behind it. */
1899 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1900 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1901 lpitem
->cxItem
-= 1;
1904 else if (!menuBar
) {
1905 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1906 lpitem
->cxItem
+= check_bitmap_width
;
1907 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1908 lpitem
->dxTab
= lpitem
->cxItem
;
1909 lpitem
->cxItem
+= arrow_bitmap_width
;
1912 /* it must be a text item - unless it's the system menu */
1913 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1914 HFONT hfontOld
= NULL
;
1915 RECT rc
;// = lpitem->Rect;
1916 LONG txtheight
, txtwidth
;
1918 rc
.left
= lpitem
->xItem
;
1919 rc
.top
= lpitem
->yItem
;
1920 rc
.right
= lpitem
->cxItem
; // Do this for now......
1921 rc
.bottom
= lpitem
->cyItem
;
1923 if ( lpitem
->fState
& MFS_DEFAULT
) {
1924 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1927 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1929 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1930 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1932 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1934 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1937 int n
= (int)( p
- lpitem
->Xlpstr
);
1938 /* Item contains a tab (only meaningful in popup menus) */
1939 /* get text size before the tab */
1940 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1941 DT_SINGLELINE
|DT_CALCRECT
);
1942 txtwidth
= rc
.right
- rc
.left
;
1943 p
+= 1; /* advance past the Tab */
1944 /* get text size after the tab */
1945 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1946 DT_SINGLELINE
|DT_CALCRECT
);
1947 lpitem
->dxTab
+= txtwidth
;
1948 txtheight
= max( txtheight
, tmpheight
);
1949 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1950 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1952 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1953 DT_SINGLELINE
|DT_CALCRECT
);
1954 txtwidth
= rc
.right
- rc
.left
;
1955 lpitem
->dxTab
+= txtwidth
;
1957 lpitem
->cxItem
+= 2 + txtwidth
;
1958 itemheight
= max( itemheight
,
1959 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1963 NtGdiSelectFont (hdc
, hfontOld
);
1965 } else if( menuBar
) {
1966 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1968 lpitem
->cyItem
+= itemheight
;
1969 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1972 /***********************************************************************
1973 * MENU_GetMaxPopupHeight
1976 MENU_GetMaxPopupHeight(PMENU lppop
)
1980 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1981 return lppop
->cyMax
;
1983 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
1984 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
1987 /***********************************************************************
1988 * MenuPopupMenuCalcSize
1990 * Calculate the size of a popup menu.
1992 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
1997 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1998 BOOL textandbmp
= FALSE
;
2000 Menu
->cxMenu
= Menu
->cyMenu
= 0;
2001 if (Menu
->cItems
== 0) return;
2003 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2005 NtGdiSelectFont( hdc
, ghMenuFont
);
2010 Menu
->cxTextAlign
= 0;
2012 while (start
< Menu
->cItems
)
2014 lpitem
= &Menu
->rgItems
[start
];
2016 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2017 orgX
+= MENU_COL_SPACE
;
2018 orgY
= MENU_TOP_MARGIN
;
2020 maxTab
= maxTabWidth
= 0;
2021 /* Parse items until column break or end of menu */
2022 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2025 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2027 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2028 maxX
= max(maxX
, lpitem
->cxItem
);
2029 orgY
= lpitem
->cyItem
;
2030 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2032 maxTab
= max( maxTab
, lpitem
->dxTab
);
2033 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2035 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2038 /* Finish the column (set all items to the largest width found) */
2039 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2040 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2042 lpitem
->cxItem
= maxX
;
2043 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2044 lpitem
->dxTab
= maxTab
;
2046 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2049 Menu
->cxMenu
= maxX
;
2050 /* if none of the items have both text and bitmap then
2051 * the text and bitmaps are all aligned on the left. If there is at
2052 * least one item with both text and bitmap then bitmaps are
2053 * on the left and texts left aligned with the right hand side
2055 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2057 /* space for 3d border */
2058 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2061 /* Adjust popup height if it exceeds maximum */
2062 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2063 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2064 if (Menu
->cyMenu
>= maxHeight
)
2066 Menu
->cyMenu
= maxHeight
;
2067 Menu
->dwArrowsOn
= 1;
2071 Menu
->dwArrowsOn
= 0;
2073 UserReleaseDC( 0, hdc
, FALSE
);
2076 /***********************************************************************
2077 * MENU_MenuBarCalcSize
2079 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2080 * height is off by 1 pixel which causes lengthy window relocations when
2081 * active document window is maximized/restored.
2083 * Calculate the size of the menu bar.
2085 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2088 UINT start
, i
, helpPos
;
2089 int orgX
, orgY
, maxY
;
2091 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2092 if (lppop
->cItems
== 0) return;
2093 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2094 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2096 maxY
= lprect
->top
+1;
2099 lppop
->cxTextAlign
= 0;
2100 while (start
< lppop
->cItems
)
2102 lpitem
= &lppop
->rgItems
[start
];
2103 orgX
= lprect
->left
;
2106 /* Parse items until line break or end of menu */
2107 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2109 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2111 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2113 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2114 //debug_print_menuitem (" item: ", lpitem, "");
2115 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2116 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2118 if (lpitem
->cxItem
> lprect
->right
)
2120 if (i
!= start
) break;
2121 else lpitem
->cxItem
= lprect
->right
;
2123 maxY
= max( maxY
, lpitem
->cyItem
);
2124 orgX
= lpitem
->cxItem
;
2127 /* Finish the line (set all items to the largest height found) */
2129 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2130 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2132 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2134 start
= i
; /* This works! */
2137 lprect
->bottom
= maxY
;
2138 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2140 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2141 /* the last item (if several lines, only move the last line) */
2142 if (helpPos
== ~0U) return;
2143 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2144 orgY
= lpitem
->yItem
;
2145 orgX
= lprect
->right
;
2146 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2147 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2148 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2149 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2150 lpitem
->cxItem
= orgX
;
2151 orgX
= lpitem
->xItem
;
2155 /***********************************************************************
2156 * MENU_DrawScrollArrows
2158 * Draw scroll arrows.
2160 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2162 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2166 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2167 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2171 rect
.right
= lppop
->cxMenu
;
2172 rect
.bottom
= arrow_bitmap_height
;
2173 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2174 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2176 dfcrc
.right
= arrow_bitmap_width
;
2177 dfcrc
.bottom
= arrow_bitmap_height
;
2178 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2180 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2181 rect
.bottom
= lppop
->cyMenu
;
2182 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2183 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2184 Flags
= DFCS_INACTIVE
;
2185 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2186 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2187 dfcrc
.right
= arrow_bitmap_width
;
2188 dfcrc
.bottom
= lppop
->cyMenu
;
2189 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2192 /***********************************************************************
2195 * Draw a single menu item.
2197 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2198 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2202 BOOL flat_menu
= FALSE
;
2204 UINT arrow_bitmap_width
= 0;
2208 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2211 if (lpitem
->fType
& MF_SYSMENU
)
2213 if (!(Wnd
->style
& WS_MINIMIZE
))
2215 NC_GetInsideRect(Wnd
, &rect
);
2216 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2221 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2222 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2226 if (lpitem
->fState
& MF_HILITE
)
2228 if(menuBar
&& !flat_menu
) {
2229 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2230 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2232 if (lpitem
->fState
& MF_GRAYED
)
2233 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2235 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2236 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2241 if (lpitem
->fState
& MF_GRAYED
)
2242 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2244 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2245 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2248 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2249 //rect = lpitem->Rect;
2250 rect
.left
= lpitem
->xItem
;
2251 rect
.top
= lpitem
->yItem
;
2252 rect
.right
= lpitem
->cxItem
; // Do this for now......
2253 rect
.bottom
= lpitem
->cyItem
;
2255 MENU_AdjustMenuItemRect(Menu
, &rect
);
2257 if (lpitem
->fType
& MF_OWNERDRAW
)
2260 ** Experimentation under Windows reveals that an owner-drawn
2261 ** menu is given the rectangle which includes the space it requested
2262 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2263 ** and a popup-menu arrow. This is the value of lpitem->rect.
2264 ** Windows will leave all drawing to the application except for
2265 ** the popup-menu arrow. Windows always draws that itself, after
2266 ** the menu owner has finished drawing.
2269 COLORREF old_bk
, old_text
;
2271 dis
.CtlType
= ODT_MENU
;
2273 dis
.itemID
= lpitem
->wID
;
2274 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2276 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2277 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2278 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2279 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2280 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2281 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2282 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2283 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2284 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2287 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2288 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2289 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2290 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2292 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2293 old_bk
= GreGetBkColor(hdc
);
2294 old_text
= GreGetTextColor(hdc
);
2295 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2296 IntGdiSetBkColor(hdc
, old_bk
);
2297 IntGdiSetTextColor(hdc
, old_text
);
2298 /* Draw the popup-menu arrow */
2299 if (!menuBar
&& lpitem
->spSubMenu
)
2302 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2303 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2304 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2309 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2311 if (lpitem
->fState
& MF_HILITE
)
2315 RECTL_vInflateRect (&rect
, -1, -1);
2316 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2317 RECTL_vInflateRect (&rect
, 1, 1);
2318 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2323 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2325 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2329 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2331 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2333 /* vertical separator */
2334 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2339 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2341 rc
.bottom
= Height
- 3;
2344 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2345 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2346 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2347 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2348 NtGdiSelectPen( hdc
, oldPen
);
2351 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2354 /* horizontal separator */
2355 if (lpitem
->fType
& MF_SEPARATOR
)
2362 rc
.top
= ( rc
.top
+ rc
.bottom
) / 2;
2365 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2366 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2367 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2368 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2369 NtGdiSelectPen( hdc
, oldPen
);
2372 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2376 /* helper lines for debugging */
2377 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2378 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2379 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2380 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2381 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2382 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2384 #if 0 // breaks mdi menu bar icons.
2386 /* calculate the bitmap rectangle in coordinates relative
2387 * to the item rectangle */
2389 if( lpitem
->hbmp
== HBMMENU_CALLBACK
)
2392 bmprc
.left
= lpitem
->Xlpstr
? MenuCharSize
.cx
: 0;
2394 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)
2396 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)
2399 bmprc
.left
= 4 + UserGetSystemMetrics(SM_CXMENUCHECK
);
2401 bmprc
.right
= bmprc
.left
+ lpitem
->cxBmp
;
2403 if( menuBar
&& !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2406 bmprc
.top
= (rect
.bottom
- rect
.top
- lpitem
->cyBmp
) / 2;
2408 bmprc
.bottom
= bmprc
.top
+ lpitem
->cyBmp
;
2414 INT y
= rect
.top
+ rect
.bottom
;
2416 BOOL checked
= FALSE
;
2417 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2418 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2419 /* Draw the check mark
2422 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2424 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2425 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2426 lpitem
->hbmpUnchecked
;
2427 if (bm
) /* we have a custom bitmap */
2429 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2431 NtGdiSelectBitmap( hdcMem
, bm
);
2432 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2433 check_bitmap_width
, check_bitmap_height
,
2434 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2435 IntGdiDeleteDC( hdcMem
, FALSE
);
2438 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2442 r
.right
= r
.left
+ check_bitmap_width
;
2443 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2444 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2445 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2449 if ( lpitem
->hbmp
)//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2451 RECT bmpRect
= rect
;
2452 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2453 bmpRect
.left
+= check_bitmap_width
+ 2;
2454 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2456 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2457 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2460 /* Draw the popup-menu arrow */
2461 if (lpitem
->spSubMenu
)
2464 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2465 rectTemp
.left
= rectTemp
.right
- check_bitmap_width
;
2466 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2469 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2470 rect
.left
+= check_bitmap_width
;
2471 rect
.right
-= arrow_bitmap_width
;
2473 else if( lpitem
->hbmp
)
2474 { /* Draw the bitmap */
2475 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
/*bmprc*/, Menu
, WndOwner
, odaction
, menuBar
);
2478 /* process text if present */
2484 UINT uFormat
= menuBar
?
2485 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2486 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2488 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2489 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2491 rect
.left
+= Menu
->cxTextAlign
;
2493 if ( lpitem
->fState
& MFS_DEFAULT
)
2495 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2500 rect
.left
+= lpitem
->cxBmp
;
2501 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2502 rect
.left
+= MenuCharSize
.cx
;
2503 rect
.right
-= MenuCharSize
.cx
;
2506 Text
= lpitem
->Xlpstr
;
2509 for (i
= 0; Text
[i
]; i
++)
2510 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2514 if(lpitem
->fState
& MF_GRAYED
)
2516 if (!(lpitem
->fState
& MF_HILITE
) )
2518 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2519 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2520 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2521 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2523 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2525 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2527 /* paint the shortcut text */
2528 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2530 if (L
'\t' == Text
[i
])
2532 rect
.left
= lpitem
->dxTab
;
2533 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2537 rect
.right
= lpitem
->dxTab
;
2538 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2541 if (lpitem
->fState
& MF_GRAYED
)
2543 if (!(lpitem
->fState
& MF_HILITE
) )
2545 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2546 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2547 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2548 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2550 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2552 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2557 NtGdiSelectFont (hdc
, hfontOld
);
2562 /***********************************************************************
2565 * Paint a popup menu.
2567 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2569 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2572 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2574 IntGetClientRect( wnd
, &rect
);
2576 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2577 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2578 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2582 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2584 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2587 BOOL flat_menu
= FALSE
;
2589 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2591 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2593 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2595 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2596 /* draw menu items */
2597 if (menu
&& menu
->cItems
)
2602 item
= menu
->rgItems
;
2603 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2605 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2606 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2608 /* draw scroll arrows */
2609 if (menu
->dwArrowsOn
)
2611 MENU_DrawScrollArrows(menu
, hdc
);
2617 NtGdiSelectBrush( hdc
, hPrevBrush
);
2622 /**********************************************************************
2625 PWND
MENU_IsMenuActive(VOID
)
2627 return ValidateHwndNoErr(top_popup
);
2630 /**********************************************************************
2633 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2635 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2637 void MENU_EndMenu( PWND pwnd
)
2640 menu
= UserGetMenuObject(top_popup_hmenu
);
2641 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2643 if (fInsideMenuLoop
&& top_popup
)
2645 fInsideMenuLoop
= FALSE
;
2649 ERR("Already in End loop\n");
2654 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2660 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2663 HFONT FontOld
= NULL
;
2664 BOOL flat_menu
= FALSE
;
2666 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2670 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2678 if (Rect
== NULL
|| !pMenu
)
2680 return UserGetSystemMetrics(SM_CYMENU
);
2683 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2685 FontOld
= NtGdiSelectFont(hDC
, Font
);
2687 if (pMenu
->cyMenu
== 0)
2689 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2692 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2694 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2696 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2697 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2698 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2699 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2701 if (pMenu
->cItems
== 0)
2703 NtGdiSelectFont(hDC
, FontOld
);
2704 return UserGetSystemMetrics(SM_CYMENU
);
2707 for (i
= 0; i
< pMenu
->cItems
; i
++)
2709 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2712 NtGdiSelectFont(hDC
, FontOld
);
2714 return pMenu
->cyMenu
;
2717 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2720 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2724 // No menu. Do not reserve any space
2730 return UserGetSystemMetrics(SM_CYMENU
);
2735 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2737 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2739 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2741 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2743 return lppop
->cyMenu
;
2747 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2751 /***********************************************************************
2754 * Popup menu initialization before WM_ENTERMENULOOP.
2756 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2759 PPOPUPMENU pPopupMenu
;
2761 LARGE_STRING WindowName
;
2762 UNICODE_STRING ClassName
;
2763 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2765 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2767 menu
->spwndNotify
= pWndOwner
;
2769 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2770 ex_style
= WS_EX_LAYOUTRTL
;
2772 ClassName
.Buffer
= WC_MENU
;
2773 ClassName
.Length
= 0;
2775 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2776 RtlZeroMemory(&Cs
, sizeof(Cs
));
2777 Cs
.style
= WS_POPUP
;
2778 Cs
.dwExStyle
= ex_style
;
2779 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2780 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2781 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2782 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2783 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2785 /* NOTE: In Windows, top menu popup is not owned. */
2786 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2788 if( !pWndCreated
) return FALSE
;
2791 // Setup pop up menu structure.
2793 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2795 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2797 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2798 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2799 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2801 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2802 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2803 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2804 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2805 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2807 if (pPopupMenu
->fRightButton
)
2808 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2810 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2812 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2813 menu
->fFlags
& MNF_RTOL
)
2815 pPopupMenu
->fDroppedLeft
= TRUE
;
2820 /***********************************************************************
2823 * Display a popup menu.
2825 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2826 INT x
, INT y
, INT xanchor
, INT yanchor
)
2832 USER_REFERENCE_ENTRY Ref
;
2834 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2835 pwndOwner
, menu
, id
, x
, y
, xanchor
, yanchor
);
2837 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2839 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2840 menu
->iItem
= NO_SELECTED_ITEM
;
2843 menu
->dwArrowsOn
= 0;
2844 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2846 /* adjust popup menu pos so that it fits within the desktop */
2848 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2849 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2851 /* FIXME: should use item rect */
2854 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2856 if (flags
& TPM_LAYOUTRTL
)
2857 flags
^= TPM_RIGHTALIGN
;
2859 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2860 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2862 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2863 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2865 if( x
+ width
> monitor
->rcMonitor
.right
)
2867 if( xanchor
&& x
>= width
- xanchor
)
2868 x
-= width
- xanchor
;
2870 if( x
+ width
> monitor
->rcMonitor
.right
)
2871 x
= monitor
->rcMonitor
.right
- width
;
2873 if( x
< monitor
->rcMonitor
.left
) x
= monitor
->rcMonitor
.left
;
2875 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2877 if( yanchor
&& y
>= height
+ yanchor
)
2878 y
-= height
+ yanchor
;
2880 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2881 y
= monitor
->rcMonitor
.bottom
- height
;
2883 if( y
< monitor
->rcMonitor
.top
) y
= monitor
->rcMonitor
.top
;
2885 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2889 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2894 top_popup
= menu
->hWnd
;
2895 top_popup_hmenu
= UserHMGetHandle(menu
);
2898 /* Display the window */
2899 UserRefObjectCo(pWnd
, &Ref
);
2900 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2902 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2904 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2905 UserDerefObjectCo(pWnd
);
2910 /***********************************************************************
2911 * MENU_EnsureMenuItemVisible
2913 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2915 USER_REFERENCE_ENTRY Ref
;
2916 if (lppop
->dwArrowsOn
)
2918 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2919 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2920 UINT nOldPos
= lppop
->iTop
;
2922 UINT arrow_bitmap_height
;
2923 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2925 IntGetClientRect(pWnd
, &rc
);
2927 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2929 rc
.top
+= arrow_bitmap_height
;
2930 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2932 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2933 UserRefObjectCo(pWnd
, &Ref
);
2934 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
2936 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
2937 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2938 MENU_DrawScrollArrows(lppop
, hdc
);
2939 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2941 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
2943 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
2944 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2945 MENU_DrawScrollArrows(lppop
, hdc
);
2946 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2948 UserDerefObjectCo(pWnd
);
2952 /***********************************************************************
2955 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
2956 BOOL sendMenuSelect
, PMENU topmenu
)
2961 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2963 if (!menu
|| !menu
->cItems
) return;
2965 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
2969 if (menu
->iItem
== wIndex
) return;
2971 if (menu
->fFlags
& MNF_POPUP
)
2972 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
2974 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2977 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
2978 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
2979 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
2982 NtGdiSelectFont( hdc
, ghMenuFont
);
2984 /* Clear previous highlighted item */
2985 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2987 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2988 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
2989 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
2993 /* Highlight new item (if any) */
2994 menu
->iItem
= wIndex
;
2995 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2997 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
2999 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
3000 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
3001 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
3002 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3006 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3007 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3008 ip
->fType
| ip
->fState
|
3009 (ip
->spSubMenu
? MF_POPUP
: 0) |
3010 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3012 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3015 else if (sendMenuSelect
)
3020 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3021 if (pos
!= NO_SELECTED_ITEM
)
3023 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3024 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3025 (ip
->spSubMenu
? MF_POPUP
: 0) |
3026 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3028 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3032 UserReleaseDC(pWnd
, hdc
, FALSE
);
3035 /***********************************************************************
3038 * Moves currently selected item according to the Offset parameter.
3039 * If there is no selection then it should select the last item if
3040 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3042 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3046 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3048 if ((!menu
) || (!menu
->rgItems
)) return;
3050 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3052 if ( menu
->cItems
== 1 )
3055 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3057 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3059 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3064 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3065 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3066 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3068 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3073 /***********************************************************************
3076 * Hide the sub-popup menus of this menu.
3078 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3079 BOOL SendMenuSelect
, UINT wFlags
)
3081 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3083 if ( Menu
&& top_popup
)
3087 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3089 Item
= &Menu
->rgItems
[Menu
->iItem
];
3090 if (!(Item
->spSubMenu
) ||
3091 !(Item
->fState
& MF_MOUSESELECT
)) return;
3092 Item
->fState
&= ~MF_MOUSESELECT
;
3097 if (Item
->spSubMenu
)
3100 if (!VerifyMenu(Item
->spSubMenu
)) return;
3101 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3102 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3103 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3104 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3105 co_UserDestroyWindow(pWnd
);
3107 /* Native returns handle to destroyed window */
3108 if (!(wFlags
& TPM_NONOTIFY
))
3110 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3111 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3114 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3115 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3117 Item
->spSubMenu
->hWnd
= NULL
;
3123 /***********************************************************************
3126 * Display the sub-menu of the selected item of this menu.
3127 * Return the handle of the submenu, or menu if no submenu to display.
3129 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3136 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3138 if (!Menu
) return Menu
;
3140 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3142 Item
= &Menu
->rgItems
[Menu
->iItem
];
3143 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3146 /* message must be sent before using item,
3147 because nearly everything may be changed by the application ! */
3149 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3150 if (!(Flags
& TPM_NONOTIFY
))
3152 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3153 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3154 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3157 Item
= &Menu
->rgItems
[Menu
->iItem
];
3158 //Rect = ItemInfo.Rect;
3159 Rect
.left
= Item
->xItem
;
3160 Rect
.top
= Item
->yItem
;
3161 Rect
.right
= Item
->cxItem
; // Do this for now......
3162 Rect
.bottom
= Item
->cyItem
;
3164 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3166 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3167 if (!(Item
->fState
& MF_HILITE
))
3169 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3170 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3172 NtGdiSelectFont(Dc
, ghMenuFont
);
3174 Item
->fState
|= MF_HILITE
;
3175 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3176 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3178 UserReleaseDC(pWnd
, Dc
, FALSE
);
3181 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3183 Item
->xItem
= Rect
.left
;
3184 Item
->yItem
= Rect
.top
;
3185 Item
->cxItem
= Rect
.right
; // Do this for now......
3186 Item
->cyItem
= Rect
.bottom
;
3188 Item
->fState
|= MF_MOUSESELECT
;
3190 if (IS_SYSTEM_MENU(Menu
))
3192 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3194 NC_GetSysPopupPos(pWnd
, &Rect
);
3195 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3196 Rect
.top
= Rect
.bottom
;
3197 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3198 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3202 IntGetWindowRect(pWnd
, &Rect
);
3203 if (Menu
->fFlags
& MNF_POPUP
)
3206 rc
.left
= Item
->xItem
;
3207 rc
.top
= Item
->yItem
;
3208 rc
.right
= Item
->cxItem
; // Do this for now......
3209 rc
.bottom
= Item
->cyItem
;
3211 MENU_AdjustMenuItemRect(Menu
, &rc
);
3213 /* The first item in the popup menu has to be at the
3214 same y position as the focused menu item */
3215 if(Flags
& TPM_LAYOUTRTL
)
3216 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3218 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3219 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3220 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3221 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3222 - UserGetSystemMetrics(SM_CYBORDER
);
3226 if(Flags
& TPM_LAYOUTRTL
)
3227 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3229 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3230 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3231 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3232 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3236 /* use default alignment for submenus */
3237 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3239 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3241 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3242 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3245 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3247 return Item
->spSubMenu
;
3250 /***********************************************************************
3251 * MenuExecFocusedItem
3253 * Execute a menu item (for instance when user pressed Enter).
3254 * Return the wID of the executed item. Otherwise, -1 indicating
3255 * that no menu item was executed, -2 if a popup is shown;
3256 * Have to receive the flags for the TrackPopupMenu options to avoid
3257 * sending unwanted message.
3260 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3264 TRACE("%p menu=%p\n", pmt
, Menu
);
3266 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3271 Item
= &Menu
->rgItems
[Menu
->iItem
];
3273 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3275 if (!(Item
->spSubMenu
))
3277 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3279 /* If TPM_RETURNCMD is set you return the id, but
3280 do not send a message to the owner */
3281 if (!(Flags
& TPM_RETURNCMD
))
3283 if (Menu
->fFlags
& MNF_SYSMENU
)
3285 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3286 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3290 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3292 if (dwStyle
& MNS_NOTIFYBYPOS
)
3293 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3295 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3303 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3310 /***********************************************************************
3311 * MenuSwitchTracking
3313 * Helper function for menu navigation routines.
3315 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3317 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3319 if ( pmt
->TopMenu
!= PtMenu
&&
3320 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3322 /* both are top level menus (system and menu-bar) */
3323 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3324 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3325 pmt
->TopMenu
= PtMenu
;
3329 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3332 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3335 /***********************************************************************
3338 * Return TRUE if we can go on with menu tracking.
3340 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3342 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3348 if (IS_SYSTEM_MENU(PtMenu
))
3350 item
= PtMenu
->rgItems
;
3354 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3359 if (PtMenu
->iItem
!= id
)
3360 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3362 /* If the popup menu is not already "popped" */
3363 if (!(item
->fState
& MF_MOUSESELECT
))
3365 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3370 /* Else the click was on the menu bar, finish the tracking */
3375 /***********************************************************************
3378 * Return the value of MenuExecFocusedItem if
3379 * the selected item was not a popup. Else open the popup.
3380 * A -1 return value indicates that we go on with menu tracking.
3383 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3385 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3392 if ( IS_SYSTEM_MENU(PtMenu
) )
3394 item
= PtMenu
->rgItems
;
3398 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3401 if (item
&& ( PtMenu
->iItem
== Id
))
3403 if (!(item
->spSubMenu
))
3405 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3406 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3407 return ExecutedMenuId
;
3410 /* If we are dealing with the menu bar */
3411 /* and this is a click on an already "popped" item: */
3412 /* Stop the menu tracking and close the opened submenus */
3413 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3418 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3420 PtMenu
->TimeToHide
= TRUE
;
3426 /***********************************************************************
3429 * Walks menu chain trying to find a menu pt maps to.
3431 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3436 if (!menu
) return NULL
;
3438 /* try subpopup first (if any) */
3439 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3441 pItem
= menu
->rgItems
;
3442 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3443 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3445 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3449 /* check the current window (avoiding WM_HITTEST) */
3452 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3453 INT ht
= GetNCHitEx(pWnd
, pt
);
3454 if ( menu
->fFlags
& MNF_POPUP
)
3456 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3458 else if (ht
== HTSYSMENU
)
3459 ret
= get_win_sys_menu(menu
->hWnd
);
3460 else if (ht
== HTMENU
)
3461 ret
= IntGetMenu( menu
->hWnd
);
3466 /***********************************************************************
3469 * Return TRUE if we can go on with menu tracking.
3471 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3473 UINT Index
= NO_SELECTED_ITEM
;
3477 if (IS_SYSTEM_MENU(PtMenu
))
3480 //// ReactOS only HACK: CORE-2338
3481 // Windows tracks mouse moves to the system menu but does not open it.
3482 // Only keyboard tracking can do that.
3484 TRACE("SystemMenu\n");
3485 return TRUE
; // Stay inside the Loop!
3488 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3491 if (Index
== NO_SELECTED_ITEM
)
3493 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3495 else if (PtMenu
->iItem
!= Index
)
3497 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3498 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3503 /***********************************************************************
3506 * Return the handle of the selected sub-popup menu (if any).
3508 static PMENU
MENU_GetSubPopup( PMENU menu
)
3512 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3514 item
= &menu
->rgItems
[menu
->iItem
];
3515 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3517 return item
->spSubMenu
;
3522 /***********************************************************************
3525 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3527 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3531 /* When skipping left, we need to do something special after the
3533 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3537 /* When skipping right, for the non-system menu, we need to
3538 handle the last non-special menu item (ie skip any window
3539 icons such as MDI maximize, restore or close) */
3540 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3542 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3543 while (i
< pmt
->TopMenu
->cItems
) {
3544 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3545 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3549 if (i
== pmt
->TopMenu
->cItems
) {
3553 /* When skipping right, we need to cater for the system menu */
3554 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3556 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3563 MDINEXTMENU NextMenu
;
3570 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3571 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3572 NextMenu
.hmenuNext
= NULL
;
3573 NextMenu
.hwndNext
= NULL
;
3574 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3576 TRACE("%p [%p] -> %p [%p]\n",
3577 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3579 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3581 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3582 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3584 /* switch to the menu bar */
3586 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3590 Id
= MenuTmp
->cItems
- 1;
3592 /* Skip backwards over any system predefined icons,
3593 eg. MDI close, restore etc icons */
3595 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3596 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3599 hNewMenu
= UserHMGetHandle(MenuTmp
);
3601 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3603 /* switch to the system menu */
3604 MenuTmp
= get_win_sys_menu(hNewWnd
);
3605 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3610 else /* application returned a new menu to switch to */
3612 hNewMenu
= NextMenu
.hmenuNext
;
3613 hNewWnd
= NextMenu
.hwndNext
;
3615 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3617 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3619 /* get the real system menu */
3620 MenuTmp
= get_win_sys_menu(hNewWnd
);
3621 hNewMenu
= UserHMGetHandle(MenuTmp
);
3623 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3625 /* FIXME: Not sure what to do here;
3626 * perhaps try to track NewMenu as a popup? */
3628 WARN(" -- got confused.\n");
3635 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3637 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3639 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3640 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3643 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3645 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3646 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3647 ///// Use thread pms!!!!
3648 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3649 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3650 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3651 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3654 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3655 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3662 /***********************************************************************
3665 * The idea is not to show the popup if the next input message is
3666 * going to hide it anyway.
3668 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3672 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3674 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3675 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3680 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3681 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3683 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3684 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3685 if( msg
.message
== WM_KEYDOWN
&&
3686 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3688 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3694 /* failures go through this */
3695 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3699 /***********************************************************************
3702 * Handle a VK_ESCAPE key event in a menu.
3704 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3706 BOOL EndMenu
= TRUE
;
3708 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3710 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3712 PMENU MenuPrev
, MenuTmp
;
3714 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3716 /* close topmost popup */
3717 while (MenuTmp
!= pmt
->CurrentMenu
)
3720 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3723 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3724 pmt
->CurrentMenu
= MenuPrev
;
3732 /***********************************************************************
3735 * Handle a VK_LEFT key event in a menu.
3737 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
, UINT msg
)
3739 PMENU MenuTmp
, MenuPrev
;
3742 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3744 /* Try to move 1 column left (if possible) */
3745 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3747 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3751 /* close topmost popup */
3752 while (MenuTmp
!= pmt
->CurrentMenu
)
3755 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3758 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3759 pmt
->CurrentMenu
= MenuPrev
;
3761 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3763 /* move menu bar selection if no more popups are left */
3765 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3766 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3768 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3770 /* A sublevel menu was displayed - display the next one
3771 * unless there is another displacement coming up */
3773 if (!MENU_SuspendPopup(pmt
, msg
))
3774 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3780 /***********************************************************************
3783 * Handle a VK_RIGHT key event in a menu.
3785 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
, UINT msg
)
3790 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3791 pmt
->CurrentMenu
, pmt
->TopMenu
);
3793 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3795 /* If already displaying a popup, try to display sub-popup */
3797 menutmp
= pmt
->CurrentMenu
;
3798 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3800 /* if subpopup was displayed then we are done */
3801 if (menutmp
!= pmt
->CurrentMenu
) return;
3804 /* Check to see if there's another column */
3805 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3807 TRACE("Going to %d.\n", NextCol
);
3808 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3812 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3814 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3816 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3817 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3824 /* try to move to the next item */
3825 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3826 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3828 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3830 if ( !MENU_SuspendPopup(pmt
, msg
) )
3831 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3836 /***********************************************************************
3839 * Menu tracking code.
3841 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3842 PWND pwnd
, const RECT
*lprect
)
3846 INT executedMenuId
= -1;
3850 BOOL enterIdleSent
= FALSE
;
3851 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3853 if (pti
!= pwnd
->head
.pti
)
3855 ERR("Not the same PTI!!!!\n");
3859 mt
.CurrentMenu
= pmenu
;
3865 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3866 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3867 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3869 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3871 if (wFlags
& TPM_BUTTONDOWN
)
3873 /* Get the result in order to start the tracking or not */
3874 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3875 fInsideMenuLoop
= fRemove
;
3878 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3880 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3882 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3883 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3884 co_UserSetCapture(NULL
); /* release the capture */
3888 capture_win
= IntGetCapture();
3890 while (fInsideMenuLoop
)
3892 BOOL ErrorExit
= FALSE
;
3893 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3896 /* we have to keep the message in the queue until it's
3897 * clear that menu loop is not over yet. */
3901 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3903 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3904 /* remove the message from the queue */
3905 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3909 /* ReactOS Checks */
3910 if (!VerifyWnd(mt
.OwnerWnd
) ||
3911 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3912 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3913 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3915 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3921 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3922 enterIdleSent
= TRUE
;
3923 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3925 co_IntWaitMessage(NULL
, 0, 0);
3929 if (ErrorExit
) break; // Gracefully dropout.
3931 /* check if EndMenu() tried to cancel us, by posting this message */
3932 if (msg
.message
== WM_CANCELMODE
)
3934 /* we are now out of the loop */
3935 fInsideMenuLoop
= FALSE
;
3937 /* remove the message from the queue */
3938 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3940 /* break out of internal loop, ala ESCAPE */
3946 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3947 enterIdleSent
=FALSE
;
3950 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3953 * Use the mouse coordinates in lParam instead of those in the MSG
3954 * struct to properly handle synthetic messages. They are already
3955 * in screen coordinates.
3957 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3958 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3960 /* Find a menu for this mouse event */
3961 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3965 /* no WM_NC... messages in captured state */
3967 case WM_RBUTTONDBLCLK
:
3968 case WM_RBUTTONDOWN
:
3969 if (!(wFlags
& TPM_RIGHTBUTTON
))
3971 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3975 case WM_LBUTTONDBLCLK
:
3976 case WM_LBUTTONDOWN
:
3977 /* If the message belongs to the menu, removes it from the queue */
3978 /* Else, end menu tracking */
3979 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3980 fInsideMenuLoop
= fRemove
;
3981 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3982 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3986 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3989 /* Check if a menu was selected by the mouse */
3992 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
3994 /* End the loop if executedMenuId is an item ID */
3995 /* or if the job was done (executedMenuId = 0). */
3996 fRemove
= (executedMenuId
!= -1);
3997 fInsideMenuLoop
= !fRemove
;
3999 /* No menu was selected by the mouse */
4000 /* if the function was called by TrackPopupMenu, continue
4001 with the menu tracking. If not, stop it */
4003 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4008 /* the selected menu item must be changed every time */
4009 /* the mouse moves. */
4012 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4014 } /* switch(msg.message) - mouse */
4016 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4018 fRemove
= TRUE
; /* Keyboard messages are always removed */
4027 fInsideMenuLoop
= FALSE
;
4032 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4033 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4037 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4038 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4039 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4040 else /* otherwise try to move selection */
4041 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4045 MENU_KeyLeft( &mt
, wFlags
, msg
.message
);
4049 MENU_KeyRight( &mt
, wFlags
, msg
.message
);
4053 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4059 hi
.cbSize
= sizeof(HELPINFO
);
4060 hi
.iContextType
= HELPINFO_MENUITEM
;
4061 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4064 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4065 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4066 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4067 hi
.MousePos
= msg
.pt
;
4068 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4073 IntTranslateKbdMessage(&msg
, 0);
4076 break; /* WM_KEYDOWN */
4084 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4086 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4087 fEndMenu
= (executedMenuId
!= -2);
4088 fInsideMenuLoop
= !fEndMenu
;
4092 /* Hack to avoid control chars. */
4093 /* We will find a better way real soon... */
4094 if (msg
.wParam
< 32) break;
4096 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4098 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4099 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4102 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4103 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4104 fEndMenu
= (executedMenuId
!= -2);
4105 fInsideMenuLoop
= !fEndMenu
;
4109 } /* switch(msg.message) - kbd */
4113 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4114 IntDispatchMessage( &msg
);
4118 if (fInsideMenuLoop
) fRemove
= TRUE
;
4120 /* finally remove message from the queue */
4122 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4123 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4124 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4127 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4128 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4129 co_UserSetCapture(NULL
); /* release the capture */
4131 /* If dropdown is still painted and the close box is clicked on
4132 then the menu will be destroyed as part of the DispatchMessage above.
4133 This will then invalidate the menu handle in mt.hTopMenu. We should
4134 check for this first. */
4135 if ( VerifyMenu( mt
.TopMenu
) )
4137 if (VerifyWnd(mt
.OwnerWnd
))
4139 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4141 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4143 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4146 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4148 co_UserDestroyWindow(pwndTM
);
4150 mt
.TopMenu
->hWnd
= NULL
;
4152 if (!(wFlags
& TPM_NONOTIFY
))
4154 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4155 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4158 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4159 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4162 /* Reset the variable for hiding menu */
4163 mt
.TopMenu
->TimeToHide
= FALSE
;
4166 EngSetLastError( ERROR_SUCCESS
);
4167 /* The return value is only used by TrackPopupMenu */
4168 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4169 if (executedMenuId
== -1) executedMenuId
= 0;
4170 return executedMenuId
;
4173 /***********************************************************************
4176 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4179 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4181 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4183 co_UserHideCaret(0);
4185 /* This makes the menus of applications built with Delphi work.
4186 * It also enables menus to be displayed in more than one window,
4187 * but there are some bugs left that need to be fixed in this case.
4191 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4195 top_popup
= Menu
->hWnd
;
4196 top_popup_hmenu
= UserHMGetHandle(Menu
);
4199 fInsideMenuLoop
= TRUE
;
4202 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4203 if (!(wFlags
& TPM_NONOTIFY
))
4205 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4209 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4211 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4212 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4213 co_UserSetCapture(capture_win
); // 2
4214 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4216 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4218 if (!(wFlags
& TPM_NONOTIFY
))
4220 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4221 /* If an app changed/recreated menu bar entries in WM_INITMENU
4222 * menu sizes will be recalculated once the menu created/shown.
4226 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4228 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4233 /***********************************************************************
4236 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4238 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4240 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4242 if (!(wFlags
& TPM_NONOTIFY
))
4243 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4245 co_UserShowCaret(0);
4248 top_popup_hmenu
= NULL
;
4253 /***********************************************************************
4254 * MenuTrackMouseMenuBar
4256 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4258 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4260 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) ); // See 74276 and CORE-12801
4261 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4263 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4265 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4266 if (VerifyMenu(pMenu
))
4268 /* map point to parent client coordinates */
4269 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4270 if (Parent
!= UserGetDesktopWindow())
4272 IntScreenToClient(Parent
, &pt
);
4275 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4276 /* fetch the window menu again, it may have changed */
4277 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4278 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4279 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4283 /***********************************************************************
4284 * MenuTrackKbdMenuBar
4286 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4288 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4290 UINT uItem
= NO_SELECTED_ITEM
;
4292 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4294 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4296 /* find window that has a menu */
4298 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4299 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4301 /* check if we have to track a system menu */
4303 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4304 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4306 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4307 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4309 wParam
|= HTSYSMENU
; /* prevent item lookup */
4312 if (!VerifyMenu( TrackMenu
)) return;
4314 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4316 /* fetch the window menu again, it may have changed */
4317 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4319 if( wChar
&& wChar
!= ' ' )
4321 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4322 if ( uItem
>= (UINT
)(-2) )
4324 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4325 /* schedule end of menu tracking */
4326 wFlags
|= TF_ENDMENU
;
4331 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4333 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4335 if( uItem
== NO_SELECTED_ITEM
)
4336 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4338 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4342 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4343 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4346 /**********************************************************************
4347 * TrackPopupMenuEx (USER32.@)
4349 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4350 PWND pWnd
, LPTPMPARAMS lpTpm
)
4353 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4355 if (pti
!= pWnd
->head
.pti
)
4357 ERR("Must be the same pti!\n");
4361 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4362 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4363 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4365 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4367 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4371 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4373 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4375 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4376 if (!(wFlags
& TPM_NONOTIFY
))
4378 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4381 if (menu
->fFlags
& MNF_SYSMENU
)
4382 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4384 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4385 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4386 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4389 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4390 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4391 co_UserSetCapture(NULL
); /* release the capture */
4394 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4398 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4399 if (pwndM
) // wine hack around this with their destroy function.
4401 if (!(pWnd
->state
& WNDS_DESTROYED
))
4402 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4406 if (!(wFlags
& TPM_NONOTIFY
))
4408 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4409 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4427 PPOPUPMENU pPopupMenu
;
4431 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4437 if (Message
!= WM_NCCREATE
)
4439 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4442 Wnd
->fnid
= FNID_MENU
;
4443 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4444 if (pPopupMenu
== NULL
)
4448 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4449 pPopupMenu
->spwndPopupMenu
= Wnd
;
4450 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4451 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4457 if (Wnd
->fnid
!= FNID_MENU
)
4459 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4462 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4470 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4471 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4475 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4476 *lResult
= MA_NOACTIVATE
;
4482 IntBeginPaint(Wnd
, &ps
);
4483 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4484 IntEndPaint(Wnd
, &ps
);
4488 case WM_PRINTCLIENT
:
4490 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4499 /* zero out global pointer in case resident popup window was destroyed. */
4502 if (UserHMGetHandle(Wnd
) == top_popup
)
4505 top_popup_hmenu
= NULL
;
4510 ERR("No Window Pop Up!\n");
4516 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4517 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4518 Wnd
->fnid
= FNID_DESTROY
;
4522 case MM_SETMENUHANDLE
: // wine'isms
4525 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4528 ERR("Bad Menu Handle\n");
4531 pPopupMenu
->spmenu
= pmenu
;
4535 case MM_GETMENUHANDLE
: // wine'isms
4537 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4541 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4543 ERR("Someone is passing unknown menu messages %d\n",Message
);
4545 TRACE("PMWP to IDWP %d\n",Message
);
4546 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4554 IntHiliteMenuItem(PWND WindowObject
,
4560 UINT uItem
= uItemHilite
;
4562 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4564 if (uHilite
& MF_HILITE
)
4566 MenuItem
->fState
|= MF_HILITE
;
4570 MenuItem
->fState
&= ~MF_HILITE
;
4572 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4573 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4574 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4576 return TRUE
; // Always returns true!!!!
4580 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4584 DWORD dwExStyle
= 0;
4585 BOOLEAN retValue
= TRUE
;
4587 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4589 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4591 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4593 dwStyle
= pWindowObject
->style
;
4594 dwExStyle
= pWindowObject
->ExStyle
;
4596 bti
->rcTitleBar
.top
= 0;
4597 bti
->rcTitleBar
.left
= 0;
4598 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4599 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4601 /* Is it iconiced ? */
4602 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4604 /* Remove frame from rectangle */
4605 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4607 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4608 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4610 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4612 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4613 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4615 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4617 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4618 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4621 /* We have additional border information if the window
4622 * is a child (but not an MDI child) */
4623 if ( (dwStyle
& WS_CHILD
) &&
4624 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4626 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4628 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4629 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4632 if (dwExStyle
& WS_EX_STATICEDGE
)
4634 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4635 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4640 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4641 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4642 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4644 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4645 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4647 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4648 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4652 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4653 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4654 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4657 if (dwStyle
& WS_CAPTION
)
4659 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4660 if (dwStyle
& WS_SYSMENU
)
4662 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4664 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4665 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4669 if (!(dwStyle
& WS_MINIMIZEBOX
))
4671 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4673 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4675 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4679 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4681 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4683 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4685 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4690 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4691 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4692 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4693 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4698 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4703 EngSetLastError(ERROR_INVALID_PARAMETER
);
4715 LPCMENUITEMINFOW UnsafeItemInfo
,
4716 PUNICODE_STRING lpstr
)
4719 ROSMENUITEMINFO ItemInfo
;
4721 /* Try to copy the whole MENUITEMINFOW structure */
4722 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4723 if (NT_SUCCESS(Status
))
4725 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4726 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4728 EngSetLastError(ERROR_INVALID_PARAMETER
);
4731 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4734 /* Try to copy without last field (not present in older versions) */
4735 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4736 if (NT_SUCCESS(Status
))
4738 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4740 EngSetLastError(ERROR_INVALID_PARAMETER
);
4743 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4744 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4747 SetLastNtError(Status
);
4751 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4756 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4761 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4763 if (pItem
->spSubMenu
)
4765 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4768 return (pItem
->fType
| pItem
->fState
);
4771 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4776 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4781 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4783 if (pItem
->spSubMenu
)
4785 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4791 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4793 PMENU menu
, pSubTarget
;
4795 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4796 return NO_SELECTED_ITEM
;
4798 pSubTarget
= UserGetMenuObject(hSubTarget
);
4800 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4802 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4808 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4810 PWINSTATION_OBJECT WinStaObject
;
4814 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4816 if (gpepCSRSS
!= CurrentProcess
)
4819 * gpepCSRSS does not have a Win32WindowStation
4822 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4828 if (!NT_SUCCESS(Status
))
4830 ERR("Validation of window station handle (%p) failed\n",
4831 CurrentProcess
->Win32WindowStation
);
4832 SetLastNtError(Status
);
4835 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4836 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4838 ERR("Desktop Window Station does not match Process one!\n");
4840 ObDereferenceObject(WinStaObject
);
4844 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4847 if (Menu
) UserDereferenceObject(Menu
);
4848 return (HMENU
)Handle
;
4856 PROSMENUITEMINFO ItemInfo
,
4858 PUNICODE_STRING lpstr
)
4863 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4865 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4870 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4874 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4884 PROSMENUITEMINFO UnsafeItemInfo
,
4886 PUNICODE_STRING lpstr
)
4889 ROSMENUITEMINFO ItemInfo
;
4894 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4895 if (! NT_SUCCESS(Status
))
4897 SetLastNtError(Status
);
4900 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4901 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4902 Size
!= sizeof(ROSMENUITEMINFO
) )
4904 EngSetLastError(ERROR_INVALID_PARAMETER
);
4907 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4908 if (! NT_SUCCESS(Status
))
4910 SetLastNtError(Status
);
4913 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4915 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4916 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4918 EngSetLastError(ERROR_INVALID_PARAMETER
);
4922 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4924 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4925 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4928 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4934 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4938 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4941 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4942 if (! NT_SUCCESS(Status
))
4944 SetLastNtError(Status
);
4956 PROSMENUINFO UnsafeMenuInfo
,
4962 ROSMENUINFO MenuInfo
;
4964 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4965 if (! NT_SUCCESS(Status
))
4967 SetLastNtError(Status
);
4970 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4972 EngSetLastError(ERROR_INVALID_PARAMETER
);
4975 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4976 if (! NT_SUCCESS(Status
))
4978 SetLastNtError(Status
);
4985 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4990 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4993 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
4994 if (! NT_SUCCESS(Status
))
4996 SetLastNtError(Status
);
5016 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5018 Rect
->left
= MenuItem
->xItem
;
5019 Rect
->top
= MenuItem
->yItem
;
5020 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5021 Rect
->bottom
= MenuItem
->cyItem
;
5025 ERR("Failed Item Lookup! %u\n", uItem
);
5031 HWND hWnd
= Menu
->hWnd
;
5032 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5035 if (Menu
->fFlags
& MNF_POPUP
)
5037 XMove
= pWnd
->rcClient
.left
;
5038 YMove
= pWnd
->rcClient
.top
;
5042 XMove
= pWnd
->rcWindow
.left
;
5043 YMove
= pWnd
->rcWindow
.top
;
5046 Rect
->left
+= XMove
;
5048 Rect
->right
+= XMove
;
5049 Rect
->bottom
+= YMove
;
5054 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5056 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5057 HMENU hSysMenu
, hNewMenu
= NULL
;
5058 ROSMENUITEMINFO ItemInfoSet
= {0};
5059 ROSMENUITEMINFO ItemInfo
= {0};
5060 UNICODE_STRING MenuName
;
5062 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5063 if (NULL
== hSysMenu
)
5067 SysMenu
= UserGetMenuObject(hSysMenu
);
5068 if (NULL
== SysMenu
)
5070 UserDestroyMenu(hSysMenu
);
5074 SysMenu
->fFlags
|= MNF_SYSMENU
;
5075 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5079 //hNewMenu = co_IntLoadSysMenuTemplate();
5080 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5082 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5083 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5087 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5088 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5089 //ERR("%wZ\n",&MenuName);
5094 IntReleaseMenuObject(SysMenu
);
5095 UserDestroyMenu(hSysMenu
);
5098 Menu
= UserGetMenuObject(hNewMenu
);
5101 IntReleaseMenuObject(SysMenu
);
5102 UserDestroyMenu(hSysMenu
);
5106 // Do the rest in here.
5108 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5110 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5111 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5112 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5113 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5114 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5115 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5116 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5117 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5118 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5119 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5121 NewMenu
= IntCloneMenu(Menu
);
5123 IntReleaseMenuObject(NewMenu
);
5124 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5126 IntDestroyMenuObject(Menu
, FALSE
);
5134 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5136 if (Window
->pcls
->style
& CS_NOCLOSE
)
5137 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5139 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5140 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5141 ItemInfo
.fType
= MF_POPUP
;
5142 ItemInfo
.fState
= MFS_ENABLED
;
5143 ItemInfo
.dwTypeData
= NULL
;
5145 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5146 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5150 ERR("failed to load system menu!\n");
5155 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5161 if (Window
->SystemMenu
)
5163 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5164 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5166 IntDestroyMenuObject(Menu
, TRUE
);
5167 Window
->SystemMenu
= NULL
;
5173 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5174 if ((!Window
->SystemMenu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5176 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5177 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5181 if (Window
->SystemMenu
)
5183 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5184 /* Store the dummy sysmenu handle to facilitate the refresh */
5185 /* of the close button if the SC_CLOSE item change */
5186 Menu
= UserGetMenuObject(hMenu
);
5189 Menu
->spwndNotify
= Window
;
5190 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5198 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5202 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5204 if (Window
->SystemMenu
)
5206 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5209 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5210 IntDestroyMenuObject(OldMenu
, TRUE
);
5214 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5216 { // Use spmenuSys too!
5217 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5220 Window
->SystemMenu
= NULL
;
5222 if (Menu
&& Window
!= Menu
->spwndNotify
)
5224 Menu
->spwndNotify
= Window
;
5236 PMENU OldMenu
, NewMenu
= NULL
;
5238 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5240 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5241 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5245 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5253 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5254 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5263 NewMenu
= IntGetMenuObject(Menu
);
5264 if (NULL
== NewMenu
)
5266 if (NULL
!= OldMenu
)
5268 IntReleaseMenuObject(OldMenu
);
5270 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5273 if (NULL
!= NewMenu
->hWnd
)
5275 /* Can't use the same menu for two windows */
5276 if (NULL
!= OldMenu
)
5278 IntReleaseMenuObject(OldMenu
);
5280 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5286 Wnd
->IDMenu
= (UINT
) Menu
;
5287 if (NULL
!= NewMenu
)
5289 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5290 IntReleaseMenuObject(NewMenu
);
5292 if (NULL
!= OldMenu
)
5294 OldMenu
->hWnd
= NULL
;
5295 IntReleaseMenuObject(OldMenu
);
5302 /* FUNCTIONS *****************************************************************/
5307 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5322 UserEnterExclusive();
5324 if(!(Window
= UserGetWindowObject(hwnd
)))
5326 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5331 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5338 Rect
.left
= leftBorder
;
5339 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5343 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5345 UserReleaseDC( 0, hdc
, FALSE
);
5356 NtUserCheckMenuItem(
5362 DECLARE_RETURN(DWORD
);
5364 TRACE("Enter NtUserCheckMenuItem\n");
5365 UserEnterExclusive();
5367 if(!(Menu
= UserGetMenuObject(hMenu
)))
5372 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5375 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5390 DECLARE_RETURN(BOOL
);
5392 TRACE("Enter NtUserDeleteMenu\n");
5393 UserEnterExclusive();
5395 if(!(Menu
= UserGetMenuObject(hMenu
)))
5400 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5403 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5409 * NtUserGetSystemMenu
5411 * The NtUserGetSystemMenu function allows the application to access the
5412 * window menu (also known as the system menu or the control menu) for
5413 * copying and modifying.
5417 * Handle to the window that will own a copy of the window menu.
5419 * Specifies the action to be taken. If this parameter is FALSE,
5420 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5421 * currently in use. The copy is initially identical to the window menu
5422 * but it can be modified.
5423 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5424 * to the default state. The previous window menu, if any, is destroyed.
5427 * If the bRevert parameter is FALSE, the return value is a handle to a
5428 * copy of the window menu. If the bRevert parameter is TRUE, the return
5436 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5440 DECLARE_RETURN(HMENU
);
5442 TRACE("Enter NtUserGetSystemMenu\n");
5445 if (!(Window
= UserGetWindowObject(hWnd
)))
5450 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5455 RETURN(Menu
->head
.h
);
5458 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5464 * NtUserSetSystemMenu
5471 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5473 BOOL Result
= FALSE
;
5476 DECLARE_RETURN(BOOL
);
5478 TRACE("Enter NtUserSetSystemMenu\n");
5479 UserEnterExclusive();
5481 if (!(Window
= UserGetWindowObject(hWnd
)))
5489 * Assign new menu handle and Up the Lock Count.
5491 if (!(Menu
= IntGetMenuObject(hMenu
)))
5496 Result
= IntSetSystemMenu(Window
, Menu
);
5499 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5504 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5513 NtUserGetTitleBarInfo(
5518 TITLEBARINFO bartitleinfo
;
5519 DECLARE_RETURN(BOOLEAN
);
5520 BOOLEAN retValue
= TRUE
;
5522 TRACE("Enter NtUserGetTitleBarInfo\n");
5523 UserEnterExclusive();
5525 /* Vaildate the windows handle */
5526 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5528 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5534 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5535 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5536 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5540 /* Fail copy the data */
5541 EngSetLastError(ERROR_INVALID_PARAMETER
);
5546 /* Get the tile bar info */
5549 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5554 /* Copy our buffer to user mode buffer bti */
5555 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5556 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5560 /* Fail copy the data */
5561 EngSetLastError(ERROR_INVALID_PARAMETER
);
5571 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5579 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5582 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5584 if(!(Menu
= UserGetMenuObject(hMenu
)))
5589 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5591 EngSetLastError(ERROR_ACCESS_DENIED
);
5594 return IntDestroyMenuObject(Menu
, FALSE
);
5605 DECLARE_RETURN(BOOL
);
5607 TRACE("Enter NtUserDestroyMenu\n");
5608 UserEnterExclusive();
5610 if(!(Menu
= UserGetMenuObject(hMenu
)))
5614 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5616 EngSetLastError(ERROR_ACCESS_DENIED
);
5619 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5622 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5631 NtUserEnableMenuItem(
5637 DECLARE_RETURN(UINT
);
5639 TRACE("Enter NtUserEnableMenuItem\n");
5640 UserEnterExclusive();
5642 if(!(Menu
= UserGetMenuObject(hMenu
)))
5647 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5650 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5662 TRACE("Enter NtUserEndMenu\n");
5663 UserEnterExclusive();
5664 /* if ( gptiCurrent->pMenuState &&
5665 gptiCurrent->pMenuState->pGlobalPopupMenu )
5667 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5670 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5673 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5675 if (fInsideMenuLoop
&& top_popup
)
5677 fInsideMenuLoop
= FALSE
;
5678 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5681 TRACE("Leave NtUserEndMenu\n");
5689 NtUserGetMenuBarInfo(
5699 PPOPUPMENU pPopupMenu
;
5700 USER_REFERENCE_ENTRY Ref
;
5701 NTSTATUS Status
= STATUS_SUCCESS
;
5703 DECLARE_RETURN(BOOL
);
5705 TRACE("Enter NtUserGetMenuBarInfo\n");
5708 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5710 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5714 UserRefObjectCo(pWnd
, &Ref
);
5716 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5718 kmbi
.hwndMenu
= NULL
;
5719 kmbi
.fBarFocused
= FALSE
;
5720 kmbi
.fFocused
= FALSE
;
5725 if (!pWnd
->pcls
->fnid
)
5727 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5729 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5730 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5733 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5734 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5735 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5736 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5738 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5740 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5745 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5746 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5747 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5750 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5751 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5752 hMenu
= UserHMGetHandle(Menu
);
5763 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5764 kmbi
.cbSize
= pmbi
->cbSize
;
5766 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5772 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5774 EngSetLastError(ERROR_INVALID_PARAMETER
);
5778 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5782 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5787 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5788 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5789 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5790 TRACE("idItem a 0 %d\n",Ret
);
5794 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5795 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5799 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5800 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5803 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5804 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5806 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5811 kmbi
.fFocused
= kmbi
.fBarFocused
;
5816 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5817 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5819 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5821 Status
= _SEH2_GetExceptionCode();
5825 if (!NT_SUCCESS(Status
))
5827 SetLastNtError(Status
);
5834 if (pWnd
) UserDerefObjectCo(pWnd
);
5835 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5848 PMENU Menu
, SubMenu
;
5851 DECLARE_RETURN(UINT
);
5853 TRACE("Enter NtUserGetMenuIndex\n");
5856 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5857 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5860 MenuItem
= Menu
->rgItems
;
5861 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5863 if (MenuItem
->spSubMenu
== SubMenu
)
5864 RETURN(MenuItem
->wID
);
5869 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5878 NtUserGetMenuItemRect(
5889 NTSTATUS Status
= STATUS_SUCCESS
;
5890 DECLARE_RETURN(BOOL
);
5892 TRACE("Enter NtUserGetMenuItemRect\n");
5895 if (!(Menu
= UserGetMenuObject(hMenu
)))
5900 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5902 Rect
.left
= MenuItem
->xItem
;
5903 Rect
.top
= MenuItem
->yItem
;
5904 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5905 Rect
.bottom
= MenuItem
->cyItem
;
5915 if (lprcItem
== NULL
) RETURN( FALSE
);
5917 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5919 if (Menu
->fFlags
& MNF_POPUP
)
5921 XMove
= ReferenceWnd
->rcClient
.left
;
5922 YMove
= ReferenceWnd
->rcClient
.top
;
5926 XMove
= ReferenceWnd
->rcWindow
.left
;
5927 YMove
= ReferenceWnd
->rcWindow
.top
;
5932 Rect
.right
+= XMove
;
5933 Rect
.bottom
+= YMove
;
5937 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5939 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5941 Status
= _SEH2_GetExceptionCode();
5945 if (!NT_SUCCESS(Status
))
5947 SetLastNtError(Status
);
5953 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5962 NtUserHiliteMenuItem(
5970 DECLARE_RETURN(BOOLEAN
);
5972 TRACE("Enter NtUserHiliteMenuItem\n");
5973 UserEnterExclusive();
5975 if(!(Window
= UserGetWindowObject(hWnd
)))
5977 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5981 if(!(Menu
= UserGetMenuObject(hMenu
)))
5983 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5987 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
5990 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
6000 NtUserDrawMenuBarTemp(
6010 NTSTATUS Status
= STATUS_SUCCESS
;
6011 DECLARE_RETURN(DWORD
);
6013 ERR("Enter NtUserDrawMenuBarTemp\n");
6014 UserEnterExclusive();
6016 if(!(Window
= UserGetWindowObject(hWnd
)))
6018 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6022 if(!(Menu
= UserGetMenuObject(hMenu
)))
6024 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6030 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6031 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6033 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6035 Status
= _SEH2_GetExceptionCode();
6039 if (Status
!= STATUS_SUCCESS
)
6041 SetLastNtError(Status
);
6045 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6048 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6057 NtUserMenuItemFromPoint(
6067 DECLARE_RETURN(int);
6069 TRACE("Enter NtUserMenuItemFromPoint\n");
6070 UserEnterExclusive();
6072 if (!(Menu
= UserGetMenuObject(hMenu
)))
6077 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6082 X
-= Window
->rcWindow
.left
;
6083 Y
-= Window
->rcWindow
.top
;
6086 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6090 Rect
.left
= mi
->xItem
;
6091 Rect
.top
= mi
->yItem
;
6092 Rect
.right
= mi
->cxItem
;
6093 Rect
.bottom
= mi
->cyItem
;
6095 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6097 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6103 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6106 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6126 UserEnterExclusive();
6128 if(!(Window
= UserGetWindowObject(hWnd
)))
6130 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6135 Rect
.left
= leftBorder
;
6136 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6140 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6157 DECLARE_RETURN(BOOL
);
6159 TRACE("Enter NtUserRemoveMenu\n");
6160 UserEnterExclusive();
6162 if(!(Menu
= UserGetMenuObject(hMenu
)))
6167 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6170 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6187 DECLARE_RETURN(BOOL
);
6189 TRACE("Enter NtUserSetMenu\n");
6190 UserEnterExclusive();
6192 if (!(Window
= UserGetWindowObject(hWnd
)))
6197 if (!IntSetMenu(Window
, Menu
, &Changed
))
6202 // Not minimized and please repaint!!!
6203 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6205 USER_REFERENCE_ENTRY Ref
;
6206 UserRefObjectCo(Window
, &Ref
);
6207 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6208 UserDerefObjectCo(Window
);
6214 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6223 NtUserSetMenuContextHelpId(
6225 DWORD dwContextHelpId
)
6228 DECLARE_RETURN(BOOL
);
6230 TRACE("Enter NtUserSetMenuContextHelpId\n");
6231 UserEnterExclusive();
6233 if(!(Menu
= UserGetMenuObject(hMenu
)))
6238 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6241 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6250 NtUserSetMenuDefaultItem(
6256 DECLARE_RETURN(BOOL
);
6258 TRACE("Enter NtUserSetMenuDefaultItem\n");
6259 UserEnterExclusive();
6261 if(!(Menu
= UserGetMenuObject(hMenu
)))
6266 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6269 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6278 NtUserSetMenuFlagRtoL(
6282 DECLARE_RETURN(BOOL
);
6284 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6285 UserEnterExclusive();
6287 if(!(Menu
= UserGetMenuObject(hMenu
)))
6292 RETURN(IntSetMenuFlagRtoL(Menu
));
6295 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6304 NtUserThunkedMenuInfo(
6309 DECLARE_RETURN(BOOL
);
6311 TRACE("Enter NtUserThunkedMenuInfo\n");
6312 UserEnterExclusive();
6314 if (!(Menu
= UserGetMenuObject(hMenu
)))
6319 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6322 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6331 NtUserThunkedMenuItemInfo(
6336 LPMENUITEMINFOW lpmii
,
6337 PUNICODE_STRING lpszCaption
)
6341 UNICODE_STRING lstrCaption
;
6342 DECLARE_RETURN(BOOL
);
6344 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6345 UserEnterExclusive();
6347 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6348 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6350 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6352 if (!(Menu
= UserGetMenuObject(hMenu
)))
6357 /* Check if we got a Caption */
6358 if (lpszCaption
&& lpszCaption
->Buffer
)
6360 /* Copy the string to kernel mode */
6361 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6364 if (!NT_SUCCESS(Status
))
6366 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6367 SetLastNtError(Status
);
6372 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6374 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6377 if (lstrCaption
.Buffer
)
6379 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6382 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6391 NtUserTrackPopupMenuEx(
6403 USER_REFERENCE_ENTRY Ref
;
6405 TRACE("Enter NtUserTrackPopupMenuEx\n");
6406 UserEnterExclusive();
6407 /* Parameter check */
6408 if (!(menu
= UserGetMenuObject( hMenu
)))
6410 ERR("TPME : Invalid Menu handle.\n");
6411 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6415 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6417 ERR("TPME : Invalid Window handle.\n");
6425 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6430 _SEH2_YIELD(goto Exit
);
6434 UserRefObjectCo(pWnd
, &Ref
);
6435 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6436 UserDerefObjectCo(pWnd
);
6439 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);