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
* sizeof(ITEM
));
782 if(!NewMenuItem
) return FALSE
;
784 RtlZeroMemory(NewMenuItem
, Source
->cItems
* 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
;
818 Destination
->cItems
= i
+ 1;
824 IntCloneMenu(PMENU Source
)
832 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
833 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
835 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
842 Menu
->fFlags
= Source
->fFlags
;
843 Menu
->cyMax
= Source
->cyMax
;
844 Menu
->hbrBack
= Source
->hbrBack
;
845 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
846 Menu
->dwMenuData
= Source
->dwMenuData
;
847 Menu
->iItem
= NO_SELECTED_ITEM
;
848 Menu
->spwndNotify
= NULL
;
854 Menu
->cxTextAlign
= 0;
855 Menu
->rgItems
= NULL
;
858 Menu
->TimeToHide
= FALSE
;
860 IntCloneMenuItems(Menu
, Source
);
866 IntSetMenuFlagRtoL(PMENU Menu
)
868 ERR("SetMenuFlagRtoL\n");
869 Menu
->fFlags
|= MNF_RTOL
;
874 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
876 Menu
->dwContextHelpId
= dwContextHelpId
;
881 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
883 if(lpmi
->fMask
& MIM_BACKGROUND
)
884 lpmi
->hbrBack
= Menu
->hbrBack
;
885 if(lpmi
->fMask
& MIM_HELPID
)
886 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
887 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
888 lpmi
->cyMax
= Menu
->cyMax
;
889 if(lpmi
->fMask
& MIM_MENUDATA
)
890 lpmi
->dwMenuData
= Menu
->dwMenuData
;
891 if(lpmi
->fMask
& MIM_STYLE
)
892 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
894 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
896 lpmi
->cItems
= Menu
->cItems
;
898 lpmi
->iItem
= Menu
->iItem
;
899 lpmi
->cxMenu
= Menu
->cxMenu
;
900 lpmi
->cyMenu
= Menu
->cyMenu
;
901 lpmi
->spwndNotify
= Menu
->spwndNotify
;
902 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
903 lpmi
->iTop
= Menu
->iTop
;
904 lpmi
->iMaxTop
= Menu
->iMaxTop
;
905 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
907 lpmi
->fFlags
= Menu
->fFlags
;
908 lpmi
->Self
= Menu
->head
.h
;
909 lpmi
->TimeToHide
= Menu
->TimeToHide
;
910 lpmi
->Wnd
= Menu
->hWnd
;
916 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
918 if(lpmi
->fMask
& MIM_BACKGROUND
)
919 Menu
->hbrBack
= lpmi
->hbrBack
;
920 if(lpmi
->fMask
& MIM_HELPID
)
921 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
922 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
923 Menu
->cyMax
= lpmi
->cyMax
;
924 if(lpmi
->fMask
& MIM_MENUDATA
)
925 Menu
->dwMenuData
= lpmi
->dwMenuData
;
926 if(lpmi
->fMask
& MIM_STYLE
)
927 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
928 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
931 PITEM item
= Menu
->rgItems
;
932 for ( i
= Menu
->cItems
; i
; i
--, item
++)
934 if ( item
->spSubMenu
)
936 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
940 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
942 Menu
->iItem
= lpmi
->iItem
;
943 Menu
->cyMenu
= lpmi
->cyMenu
;
944 Menu
->cxMenu
= lpmi
->cxMenu
;
945 Menu
->spwndNotify
= lpmi
->spwndNotify
;
946 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
947 Menu
->iTop
= lpmi
->iTop
;
948 Menu
->iMaxTop
= lpmi
->iMaxTop
;
949 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
951 Menu
->TimeToHide
= lpmi
->TimeToHide
;
952 Menu
->hWnd
= lpmi
->Wnd
;
954 if ( lpmi
->fMask
& MIM_STYLE
)
956 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
957 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
958 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
964 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
965 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
969 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
971 lpmii
->fType
= MenuItem
->fType
;
973 if(lpmii
->fMask
& MIIM_BITMAP
)
975 lpmii
->hbmpItem
= MenuItem
->hbmp
;
977 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
979 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
980 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
982 if(lpmii
->fMask
& MIIM_DATA
)
984 lpmii
->dwItemData
= MenuItem
->dwItemData
;
986 if(lpmii
->fMask
& MIIM_ID
)
988 lpmii
->wID
= MenuItem
->wID
;
990 if(lpmii
->fMask
& MIIM_STATE
)
992 lpmii
->fState
= MenuItem
->fState
;
994 if(lpmii
->fMask
& MIIM_SUBMENU
)
996 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
999 if ((lpmii
->fMask
& MIIM_STRING
) ||
1000 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1002 if (lpmii
->dwTypeData
== NULL
)
1004 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1007 { //// lpmii->lpstr can be read in user mode!!!!
1008 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1009 min(lpmii
->cch
* sizeof(WCHAR
),
1010 MenuItem
->lpstr
.MaximumLength
));
1011 if (! NT_SUCCESS(Status
))
1013 SetLastNtError(Status
);
1019 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1021 lpmii
->Rect
.left
= MenuItem
->xItem
;
1022 lpmii
->Rect
.top
= MenuItem
->yItem
;
1023 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1024 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1025 lpmii
->dxTab
= MenuItem
->dxTab
;
1026 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1027 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1028 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1035 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1037 PMENU SubMenuObject
;
1038 BOOL circref
= FALSE
;
1040 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1044 if ( lpmii
->fMask
& MIIM_FTYPE
)
1046 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1047 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1049 if (lpmii
->fMask
& MIIM_TYPE
)
1051 #if 0 //// Done in User32.
1052 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1054 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1055 KeRosDumpStackFrames(NULL
, 20);
1056 /* This does not happen on Win9x/ME */
1057 SetLastNtError( ERROR_INVALID_PARAMETER
);
1062 * Delete the menu item type when changing type from
1065 if (MenuItem
->fType
!= lpmii
->fType
&&
1066 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1068 FreeMenuText(MenuObject
,MenuItem
);
1069 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1070 MenuItem
->Xlpstr
= NULL
;
1072 if(lpmii
->fType
& MFT_BITMAP
)
1075 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1077 { /* Win 9x/Me stuff */
1078 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1080 lpmii
->dwTypeData
= 0;
1083 if(lpmii
->fMask
& MIIM_BITMAP
)
1085 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1086 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1087 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1089 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1091 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1093 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1094 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1096 if(lpmii
->fMask
& MIIM_DATA
)
1098 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1100 if(lpmii
->fMask
& MIIM_ID
)
1102 MenuItem
->wID
= lpmii
->wID
;
1104 if(lpmii
->fMask
& MIIM_STATE
)
1106 /* Remove MFS_DEFAULT flag from all other menu items if this item
1107 has the MFS_DEFAULT state */
1108 if(lpmii
->fState
& MFS_DEFAULT
)
1109 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1110 /* Update the menu item state flags */
1111 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1114 if(lpmii
->fMask
& MIIM_SUBMENU
)
1116 if (lpmii
->hSubMenu
)
1118 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1119 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1121 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1123 if (MenuObject
== SubMenuObject
)
1126 ERR("Pop Up Menu Double Trouble!\n");
1127 SubMenuObject
= IntCreateMenu(&hMenu
,
1129 MenuObject
->head
.rpdesk
,
1130 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1131 if (!SubMenuObject
) return FALSE
;
1132 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1135 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1137 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1138 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1141 /* Make sure the submenu is marked as a popup menu */
1142 SubMenuObject
->fFlags
|= MNF_POPUP
;
1143 // Now fix the test_subpopup_locked_by_menu tests....
1144 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1145 MenuItem
->spSubMenu
= SubMenuObject
;
1146 UserReferenceObject(SubMenuObject
);
1150 EngSetLastError( ERROR_INVALID_PARAMETER
);
1155 { // If submenu just dereference it.
1156 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1157 MenuItem
->spSubMenu
= NULL
;
1161 if ((lpmii
->fMask
& MIIM_STRING
) ||
1162 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1164 /* free the string when used */
1165 FreeMenuText(MenuObject
,MenuItem
);
1166 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1167 MenuItem
->Xlpstr
= NULL
;
1169 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1171 UNICODE_STRING Source
;
1173 if (!NT_VERIFY(lpmii
->cch
<= UNICODE_STRING_MAX_CHARS
))
1178 Source
.Length
= Source
.MaximumLength
= (USHORT
)(lpmii
->cch
* sizeof(WCHAR
));
1179 Source
.Buffer
= lpmii
->dwTypeData
;
1181 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1182 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1184 MenuItem
->lpstr
.Length
= 0;
1185 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1186 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1187 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1189 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1190 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1195 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1196 !MenuItem
->Xlpstr
&&
1197 !lpmii
->dwTypeData
&&
1198 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1200 MenuItem
->fType
|= MFT_SEPARATOR
;
1202 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1204 MenuItem
->xItem
= lpmii
->Rect
.left
;
1205 MenuItem
->yItem
= lpmii
->Rect
.top
;
1206 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1207 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1208 MenuItem
->dxTab
= lpmii
->dxTab
;
1209 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1210 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1211 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1219 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1224 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1226 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1228 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1230 /* If the close item in the system menu change update the close button */
1233 switch (MenuItem
->wID
) // More than just close.
1241 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1243 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1245 /* Refresh the frame to reflect the change */
1246 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1248 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1251 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1261 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1266 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1268 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1270 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1276 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1279 PITEM MenuItem
= MenuObject
->rgItems
;
1281 if (!MenuItem
) return FALSE
;
1283 /* reset all default-item flags */
1284 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1286 MenuItem
->fState
&= ~MFS_DEFAULT
;
1289 /* no default item */
1290 if(uItem
== (UINT
)-1)
1294 MenuItem
= MenuObject
->rgItems
;
1297 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1298 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1303 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1305 if (MenuItem
->wID
== uItem
)
1307 MenuItem
->fState
|= MFS_DEFAULT
;
1317 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1320 PITEM MenuItem
= MenuObject
->rgItems
;
1323 if (!MenuItem
) return -1;
1325 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1328 if (i
>= MenuObject
->cItems
) return -1;
1331 /* default: don't return disabled items */
1332 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1334 /* search rekursiv when needed */
1335 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1339 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1341 if ( -1 != ret
) return ret
;
1343 /* when item not found in submenu, return the popup item */
1345 return ( fByPos
) ? i
: MenuItem
->wID
;
1355 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1356 return pItem
->spSubMenu
;
1359 /***********************************************************************
1360 * MenuInitSysMenuPopup
1362 * Grey the appropriate items in System menu.
1364 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1369 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1370 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1371 gray
= ((style
& WS_MAXIMIZE
) != 0);
1372 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1373 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1374 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1375 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1376 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1377 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1378 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1379 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1381 /* The menu item must keep its state if it's disabled */
1383 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1385 /* Set default menu item */
1386 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1387 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1388 else DefItem
= SC_CLOSE
;
1390 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1394 /***********************************************************************
1395 * MenuDrawPopupGlyph
1397 * Draws popup magic glyphs (can be found in system menu).
1399 static void FASTCALL
1400 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1403 HFONT hFont
, hOldFont
;
1409 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1412 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1415 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1418 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1422 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1425 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1426 RECTL_vInflateRect(r
, -2, -2);
1427 lf
.lfHeight
= r
->bottom
- r
->top
;
1429 lf
.lfWeight
= FW_NORMAL
;
1430 lf
.lfCharSet
= DEFAULT_CHARSET
;
1431 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1432 hFont
= GreCreateFontIndirectW(&lf
);
1433 /* save font and text color */
1434 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1435 clrsave
= GreGetTextColor(dc
);
1436 bkmode
= GreGetBkMode(dc
);
1437 /* set color and drawing mode */
1438 IntGdiSetBkMode(dc
, TRANSPARENT
);
1444 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1445 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1448 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1449 /* draw selected symbol */
1450 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1451 /* restore previous settings */
1452 IntGdiSetTextColor(dc
, clrsave
);
1453 NtGdiSelectFont(dc
, hOldFont
);
1454 IntGdiSetBkMode(dc
, bkmode
);
1455 GreDeleteObject(hFont
);
1458 /***********************************************************************
1459 * MENU_AdjustMenuItemRect
1461 * Adjust menu item rectangle according to scrolling state.
1464 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1466 if (menu
->dwArrowsOn
)
1468 UINT arrow_bitmap_height
;
1469 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1470 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1471 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1475 /***********************************************************************
1476 * MENU_FindItemByCoords
1478 * Find the item at the specified coordinates (screen coords). Does
1479 * not work for child windows and therefore should not be called for
1480 * an arbitrary system menu.
1482 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1487 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1489 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1490 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1491 pt
.x
= rect
.right
- 1 - pt
.x
;
1495 item
= menu
->rgItems
;
1496 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1498 //rect = item->rect;
1499 rect
.left
= item
->xItem
;
1500 rect
.top
= item
->yItem
;
1501 rect
.right
= item
->cxItem
; // Do this for now......
1502 rect
.bottom
= item
->cyItem
;
1504 MENU_AdjustMenuItemRect(menu
, &rect
);
1505 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1514 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1516 MENU
*menu
= UserGetMenuObject(hMenu
);
1519 /*FIXME: Do we have to handle hWnd here? */
1520 if (!menu
) return -1;
1521 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1525 /***********************************************************************
1528 * Find the menu item selected by a key press.
1529 * Return item id, -1 if none, -2 if we should close the menu.
1531 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1532 WCHAR Key
, BOOL ForceMenuChar
)
1537 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1539 if (!menu
|| !VerifyMenu(menu
))
1540 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1543 ITEM
*item
= menu
->rgItems
;
1545 if ( !ForceMenuChar
)
1548 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1550 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1552 LPWSTR text
= item
->Xlpstr
;
1555 const WCHAR
*p
= text
- 2;
1558 const WCHAR
*q
= p
+ 2;
1559 p
= wcschr (q
, '&');
1560 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1562 while (p
!= NULL
&& p
[1] == '&');
1563 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1568 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1569 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1571 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1572 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1573 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1574 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1579 /***********************************************************************
1580 * MenuGetBitmapItemSize
1582 * Get the size of a bitmap item.
1584 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1587 HBITMAP bmp
= lpitem
->hbmp
;
1589 size
->cx
= size
->cy
= 0;
1591 /* check if there is a magic menu item associated with this item */
1592 if (IS_MAGIC_BITMAP(bmp
))
1594 switch((INT_PTR
) bmp
)
1596 case (INT_PTR
)HBMMENU_CALLBACK
:
1598 MEASUREITEMSTRUCT measItem
;
1599 measItem
.CtlType
= ODT_MENU
;
1601 measItem
.itemID
= lpitem
->wID
;
1602 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1603 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1604 measItem
.itemData
= lpitem
->dwItemData
;
1605 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1606 size
->cx
= measItem
.itemWidth
;
1607 size
->cy
= measItem
.itemHeight
;
1608 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1613 case (INT_PTR
) HBMMENU_SYSTEM
:
1614 if (lpitem
->dwItemData
)
1616 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1620 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1621 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1622 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1623 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1624 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1625 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1626 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1627 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1628 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1629 /* FIXME: Why we need to subtract these magic values? */
1630 /* to make them smaller than the menu bar? */
1631 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1632 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1637 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1639 size
->cx
= bm
.bmWidth
;
1640 size
->cy
= bm
.bmHeight
;
1644 /***********************************************************************
1645 * MenuDrawBitmapItem
1647 * Draw a bitmap item.
1649 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1650 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1656 int w
= rect
->right
- rect
->left
;
1657 int h
= rect
->bottom
- rect
->top
;
1658 int bmp_xoffset
= 0;
1660 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1663 /* Check if there is a magic menu item associated with this item */
1664 if (IS_MAGIC_BITMAP(hbmToDraw
))
1670 switch ((INT_PTR
)hbmToDraw
)
1672 case (INT_PTR
)HBMMENU_SYSTEM
:
1673 if (lpitem
->dwItemData
)
1675 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1677 ERR("Get Item Data from this Window!!!\n");
1680 ERR("Draw Bitmap\n");
1681 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1682 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1686 PCURICON_OBJECT pIcon
= NULL
;
1687 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1689 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1690 /* only use right half of the bitmap */
1691 //bmp_xoffset = bm.bmWidth / 2;
1692 //bm.bmWidth -= bmp_xoffset;
1695 pIcon
= NC_IconForWindow(WndOwner
);
1696 // FIXME: NC_IconForWindow should reference it for us */
1697 if (pIcon
) UserReferenceObject(pIcon
);
1702 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1703 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1704 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1705 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1706 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1707 UserDereferenceObject(pIcon
);
1712 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1713 flags
= DFCS_CAPTIONRESTORE
;
1715 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1717 flags
= DFCS_CAPTIONMIN
;
1719 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1721 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1723 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1724 flags
= DFCS_CAPTIONCLOSE
;
1726 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1727 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1729 case (INT_PTR
)HBMMENU_CALLBACK
:
1731 DRAWITEMSTRUCT drawItem
;
1733 drawItem
.CtlType
= ODT_MENU
;
1735 drawItem
.itemID
= lpitem
->wID
;
1736 drawItem
.itemAction
= odaction
;
1737 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1738 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1739 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1740 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1741 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1742 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1743 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1744 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1746 drawItem
.rcItem
= *rect
;
1747 drawItem
.itemData
= lpitem
->dwItemData
;
1748 /* some applications make this assumption on the DC's origin */
1749 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1750 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1751 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1752 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1757 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1758 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1759 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1760 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1761 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1764 RECTL_vInflateRect(&r
, -1, -1);
1765 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1766 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1770 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1773 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1774 NtGdiSelectBitmap( hdcMem
, bmp
);
1775 /* handle fontsize > bitmap_height */
1776 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1778 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1779 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1780 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1781 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1782 IntGdiDeleteDC( hdcMem
, FALSE
);
1786 IntGetDialogBaseUnits(VOID
)
1795 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1797 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1798 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1799 UserReleaseDC( 0, hdc
, FALSE
);
1806 /***********************************************************************
1809 * Calculate the size of the menu item and store it in lpitem->rect.
1811 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1812 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1815 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1816 UINT arrow_bitmap_width
;
1820 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1822 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1824 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1826 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1828 if (lpitem
->fType
& MF_OWNERDRAW
)
1830 MEASUREITEMSTRUCT mis
;
1831 mis
.CtlType
= ODT_MENU
;
1833 mis
.itemID
= lpitem
->wID
;
1834 mis
.itemData
= lpitem
->dwItemData
;
1835 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1837 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1838 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1839 * width of a menufont character to the width of an owner-drawn menu.
1841 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1843 /* under at least win95 you seem to be given a standard
1844 height for the menu and the height value is ignored */
1845 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1847 Rect
.bottom
+= mis
.itemHeight
;
1849 //lpitem->cxBmp = mis.itemWidth;
1850 //lpitem->cyBmp = mis.itemHeight;
1851 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1852 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1853 lpitem
->wID
, Rect
.right
-Rect
.left
,
1854 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1856 lpitem
->xItem
= Rect
.left
;
1857 lpitem
->yItem
= Rect
.top
;
1858 lpitem
->cxItem
= Rect
.right
;
1859 lpitem
->cyItem
= Rect
.bottom
;
1864 lpitem
->xItem
= orgX
;
1865 lpitem
->yItem
= orgY
;
1866 lpitem
->cxItem
= orgX
;
1867 lpitem
->cyItem
= orgY
;
1869 if (lpitem
->fType
& MF_SEPARATOR
)
1871 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1873 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1884 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1885 /* Keep the size of the bitmap in callback mode to be able
1886 * to draw it correctly */
1887 lpitem
->cxBmp
= size
.cx
;
1888 lpitem
->cyBmp
= size
.cy
;
1889 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1890 lpitem
->cxItem
+= size
.cx
+ 2;
1891 itemheight
= size
.cy
+ 2;
1893 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1894 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1895 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1896 lpitem
->dxTab
= lpitem
->cxItem
;
1897 lpitem
->cxItem
+= arrow_bitmap_width
;
1898 } else /* hbmpItem & MenuBar */ {
1899 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1900 lpitem
->cxItem
+= size
.cx
;
1901 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1902 itemheight
= size
.cy
;
1904 /* Special case: Minimize button doesn't have a space behind it. */
1905 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1906 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1907 lpitem
->cxItem
-= 1;
1910 else if (!menuBar
) {
1911 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1912 lpitem
->cxItem
+= check_bitmap_width
;
1913 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1914 lpitem
->dxTab
= lpitem
->cxItem
;
1915 lpitem
->cxItem
+= arrow_bitmap_width
;
1918 /* it must be a text item - unless it's the system menu */
1919 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1920 HFONT hfontOld
= NULL
;
1921 RECT rc
;// = lpitem->Rect;
1922 LONG txtheight
, txtwidth
;
1924 rc
.left
= lpitem
->xItem
;
1925 rc
.top
= lpitem
->yItem
;
1926 rc
.right
= lpitem
->cxItem
; // Do this for now......
1927 rc
.bottom
= lpitem
->cyItem
;
1929 if ( lpitem
->fState
& MFS_DEFAULT
) {
1930 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1933 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1935 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1936 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1938 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1940 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1943 int n
= (int)( p
- lpitem
->Xlpstr
);
1944 /* Item contains a tab (only meaningful in popup menus) */
1945 /* get text size before the tab */
1946 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1947 DT_SINGLELINE
|DT_CALCRECT
);
1948 txtwidth
= rc
.right
- rc
.left
;
1949 p
+= 1; /* advance past the Tab */
1950 /* get text size after the tab */
1951 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1952 DT_SINGLELINE
|DT_CALCRECT
);
1953 lpitem
->dxTab
+= txtwidth
;
1954 txtheight
= max( txtheight
, tmpheight
);
1955 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1956 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1958 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1959 DT_SINGLELINE
|DT_CALCRECT
);
1960 txtwidth
= rc
.right
- rc
.left
;
1961 lpitem
->dxTab
+= txtwidth
;
1963 lpitem
->cxItem
+= 2 + txtwidth
;
1964 itemheight
= max( itemheight
,
1965 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1969 NtGdiSelectFont (hdc
, hfontOld
);
1971 } else if( menuBar
) {
1972 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1974 lpitem
->cyItem
+= itemheight
;
1975 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1978 /***********************************************************************
1979 * MENU_GetMaxPopupHeight
1982 MENU_GetMaxPopupHeight(PMENU lppop
)
1986 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1987 return lppop
->cyMax
;
1989 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
1990 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
1993 /***********************************************************************
1994 * MenuPopupMenuCalcSize
1996 * Calculate the size of a popup menu.
1998 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
2003 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
2004 BOOL textandbmp
= FALSE
;
2006 Menu
->cxMenu
= Menu
->cyMenu
= 0;
2007 if (Menu
->cItems
== 0) return;
2009 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2011 NtGdiSelectFont( hdc
, ghMenuFont
);
2016 Menu
->cxTextAlign
= 0;
2018 while (start
< Menu
->cItems
)
2020 lpitem
= &Menu
->rgItems
[start
];
2022 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2023 orgX
+= MENU_COL_SPACE
;
2024 orgY
= MENU_TOP_MARGIN
;
2026 maxTab
= maxTabWidth
= 0;
2027 /* Parse items until column break or end of menu */
2028 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2031 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2033 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2034 maxX
= max(maxX
, lpitem
->cxItem
);
2035 orgY
= lpitem
->cyItem
;
2036 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2038 maxTab
= max( maxTab
, lpitem
->dxTab
);
2039 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2041 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2044 /* Finish the column (set all items to the largest width found) */
2045 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2046 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2048 lpitem
->cxItem
= maxX
;
2049 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2050 lpitem
->dxTab
= maxTab
;
2052 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2055 Menu
->cxMenu
= maxX
;
2056 /* if none of the items have both text and bitmap then
2057 * the text and bitmaps are all aligned on the left. If there is at
2058 * least one item with both text and bitmap then bitmaps are
2059 * on the left and texts left aligned with the right hand side
2061 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2063 /* space for 3d border */
2064 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2067 /* Adjust popup height if it exceeds maximum */
2068 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2069 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2070 if (Menu
->cyMenu
>= maxHeight
)
2072 Menu
->cyMenu
= maxHeight
;
2073 Menu
->dwArrowsOn
= 1;
2077 Menu
->dwArrowsOn
= 0;
2079 UserReleaseDC( 0, hdc
, FALSE
);
2082 /***********************************************************************
2083 * MENU_MenuBarCalcSize
2085 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2086 * height is off by 1 pixel which causes lengthy window relocations when
2087 * active document window is maximized/restored.
2089 * Calculate the size of the menu bar.
2091 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2094 UINT start
, i
, helpPos
;
2095 int orgX
, orgY
, maxY
;
2097 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2098 if (lppop
->cItems
== 0) return;
2099 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2100 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2102 maxY
= lprect
->top
+1;
2105 lppop
->cxTextAlign
= 0;
2106 while (start
< lppop
->cItems
)
2108 lpitem
= &lppop
->rgItems
[start
];
2109 orgX
= lprect
->left
;
2112 /* Parse items until line break or end of menu */
2113 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2115 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2117 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2119 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2120 //debug_print_menuitem (" item: ", lpitem, "");
2121 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2122 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2124 if (lpitem
->cxItem
> lprect
->right
)
2126 if (i
!= start
) break;
2127 else lpitem
->cxItem
= lprect
->right
;
2129 maxY
= max( maxY
, lpitem
->cyItem
);
2130 orgX
= lpitem
->cxItem
;
2133 /* Finish the line (set all items to the largest height found) */
2135 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2136 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2138 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2140 start
= i
; /* This works! */
2143 lprect
->bottom
= maxY
;
2144 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2146 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2147 /* the last item (if several lines, only move the last line) */
2148 if (helpPos
== ~0U) return;
2149 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2150 orgY
= lpitem
->yItem
;
2151 orgX
= lprect
->right
;
2152 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2153 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2154 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2155 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2156 lpitem
->cxItem
= orgX
;
2157 orgX
= lpitem
->xItem
;
2161 /***********************************************************************
2162 * MENU_DrawScrollArrows
2164 * Draw scroll arrows.
2166 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2168 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2172 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2173 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2177 rect
.right
= lppop
->cxMenu
;
2178 rect
.bottom
= arrow_bitmap_height
;
2179 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2180 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2182 dfcrc
.right
= arrow_bitmap_width
;
2183 dfcrc
.bottom
= arrow_bitmap_height
;
2184 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2186 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2187 rect
.bottom
= lppop
->cyMenu
;
2188 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2189 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2190 Flags
= DFCS_INACTIVE
;
2191 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2192 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2193 dfcrc
.right
= arrow_bitmap_width
;
2194 dfcrc
.bottom
= lppop
->cyMenu
;
2195 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2198 /***********************************************************************
2201 * Draw a single menu item.
2203 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2204 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2208 BOOL flat_menu
= FALSE
;
2210 UINT arrow_bitmap_width
= 0;
2214 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2217 if (lpitem
->fType
& MF_SYSMENU
)
2219 if (!(Wnd
->style
& WS_MINIMIZE
))
2221 NC_GetInsideRect(Wnd
, &rect
);
2222 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2227 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2228 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2232 if (lpitem
->fState
& MF_HILITE
)
2234 if(menuBar
&& !flat_menu
) {
2235 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2236 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2238 if (lpitem
->fState
& MF_GRAYED
)
2239 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2241 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2242 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2247 if (lpitem
->fState
& MF_GRAYED
)
2248 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2250 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2251 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2254 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2255 //rect = lpitem->Rect;
2256 rect
.left
= lpitem
->xItem
;
2257 rect
.top
= lpitem
->yItem
;
2258 rect
.right
= lpitem
->cxItem
; // Do this for now......
2259 rect
.bottom
= lpitem
->cyItem
;
2261 MENU_AdjustMenuItemRect(Menu
, &rect
);
2263 if (lpitem
->fType
& MF_OWNERDRAW
)
2266 ** Experimentation under Windows reveals that an owner-drawn
2267 ** menu is given the rectangle which includes the space it requested
2268 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2269 ** and a popup-menu arrow. This is the value of lpitem->rect.
2270 ** Windows will leave all drawing to the application except for
2271 ** the popup-menu arrow. Windows always draws that itself, after
2272 ** the menu owner has finished drawing.
2275 COLORREF old_bk
, old_text
;
2277 dis
.CtlType
= ODT_MENU
;
2279 dis
.itemID
= lpitem
->wID
;
2280 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2282 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2283 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2284 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2285 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2286 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2287 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2288 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2289 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2290 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2293 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2294 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2295 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2296 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2298 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2299 old_bk
= GreGetBkColor(hdc
);
2300 old_text
= GreGetTextColor(hdc
);
2301 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2302 IntGdiSetBkColor(hdc
, old_bk
);
2303 IntGdiSetTextColor(hdc
, old_text
);
2304 /* Draw the popup-menu arrow */
2305 if (!menuBar
&& lpitem
->spSubMenu
)
2308 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2309 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2310 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2315 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2317 if (lpitem
->fState
& MF_HILITE
)
2321 RECTL_vInflateRect (&rect
, -1, -1);
2322 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2323 RECTL_vInflateRect (&rect
, 1, 1);
2324 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2329 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2331 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2335 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2337 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2339 /* vertical separator */
2340 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2345 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2347 rc
.bottom
= Height
- 3;
2350 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2351 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2352 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2353 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2354 NtGdiSelectPen( hdc
, oldPen
);
2357 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2360 /* horizontal separator */
2361 if (lpitem
->fType
& MF_SEPARATOR
)
2368 rc
.top
= ( rc
.top
+ rc
.bottom
) / 2;
2371 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2372 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2373 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2374 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2375 NtGdiSelectPen( hdc
, oldPen
);
2378 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2382 /* helper lines for debugging */
2383 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2384 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2385 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2386 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2387 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2388 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2390 #if 0 // breaks mdi menu bar icons.
2392 /* calculate the bitmap rectangle in coordinates relative
2393 * to the item rectangle */
2395 if( lpitem
->hbmp
== HBMMENU_CALLBACK
)
2398 bmprc
.left
= lpitem
->Xlpstr
? MenuCharSize
.cx
: 0;
2400 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)
2402 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)
2405 bmprc
.left
= 4 + UserGetSystemMetrics(SM_CXMENUCHECK
);
2407 bmprc
.right
= bmprc
.left
+ lpitem
->cxBmp
;
2409 if( menuBar
&& !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2412 bmprc
.top
= (rect
.bottom
- rect
.top
- lpitem
->cyBmp
) / 2;
2414 bmprc
.bottom
= bmprc
.top
+ lpitem
->cyBmp
;
2420 INT y
= rect
.top
+ rect
.bottom
;
2422 BOOL checked
= FALSE
;
2423 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2424 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2425 /* Draw the check mark
2428 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2430 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2431 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2432 lpitem
->hbmpUnchecked
;
2433 if (bm
) /* we have a custom bitmap */
2435 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2437 NtGdiSelectBitmap( hdcMem
, bm
);
2438 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2439 check_bitmap_width
, check_bitmap_height
,
2440 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2441 IntGdiDeleteDC( hdcMem
, FALSE
);
2444 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2448 r
.right
= r
.left
+ check_bitmap_width
;
2449 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2450 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2451 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2455 if ( lpitem
->hbmp
)//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2457 RECT bmpRect
= rect
;
2458 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2459 bmpRect
.left
+= check_bitmap_width
+ 2;
2460 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2462 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2463 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2466 /* Draw the popup-menu arrow */
2467 if (lpitem
->spSubMenu
)
2470 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2471 rectTemp
.left
= rectTemp
.right
- check_bitmap_width
;
2472 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2475 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2476 rect
.left
+= check_bitmap_width
;
2477 rect
.right
-= arrow_bitmap_width
;
2479 else if( lpitem
->hbmp
)
2480 { /* Draw the bitmap */
2481 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
/*bmprc*/, Menu
, WndOwner
, odaction
, menuBar
);
2484 /* process text if present */
2490 UINT uFormat
= menuBar
?
2491 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2492 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2494 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2495 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2497 rect
.left
+= Menu
->cxTextAlign
;
2499 if ( lpitem
->fState
& MFS_DEFAULT
)
2501 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2506 rect
.left
+= lpitem
->cxBmp
;
2507 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2508 rect
.left
+= MenuCharSize
.cx
;
2509 rect
.right
-= MenuCharSize
.cx
;
2512 Text
= lpitem
->Xlpstr
;
2515 for (i
= 0; Text
[i
]; i
++)
2516 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2520 if(lpitem
->fState
& MF_GRAYED
)
2522 if (!(lpitem
->fState
& MF_HILITE
) )
2524 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2525 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2526 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2527 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2529 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2531 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2533 /* paint the shortcut text */
2534 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2536 if (L
'\t' == Text
[i
])
2538 rect
.left
= lpitem
->dxTab
;
2539 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2543 rect
.right
= lpitem
->dxTab
;
2544 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2547 if (lpitem
->fState
& MF_GRAYED
)
2549 if (!(lpitem
->fState
& MF_HILITE
) )
2551 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2552 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2553 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2554 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2556 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2558 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2563 NtGdiSelectFont (hdc
, hfontOld
);
2568 /***********************************************************************
2571 * Paint a popup menu.
2573 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2575 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2578 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2580 IntGetClientRect( wnd
, &rect
);
2582 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2583 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2584 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2588 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2590 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2593 BOOL flat_menu
= FALSE
;
2595 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2597 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2599 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2601 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2602 /* draw menu items */
2603 if (menu
&& menu
->cItems
)
2608 item
= menu
->rgItems
;
2609 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2611 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2612 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2614 /* draw scroll arrows */
2615 if (menu
->dwArrowsOn
)
2617 MENU_DrawScrollArrows(menu
, hdc
);
2623 NtGdiSelectBrush( hdc
, hPrevBrush
);
2628 /**********************************************************************
2631 PWND
MENU_IsMenuActive(VOID
)
2633 return ValidateHwndNoErr(top_popup
);
2636 /**********************************************************************
2639 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2641 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2643 void MENU_EndMenu( PWND pwnd
)
2646 menu
= UserGetMenuObject(top_popup_hmenu
);
2647 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2649 if (fInsideMenuLoop
&& top_popup
)
2651 fInsideMenuLoop
= FALSE
;
2655 ERR("Already in End loop\n");
2660 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2666 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2669 HFONT FontOld
= NULL
;
2670 BOOL flat_menu
= FALSE
;
2672 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2676 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2684 if (Rect
== NULL
|| !pMenu
)
2686 return UserGetSystemMetrics(SM_CYMENU
);
2689 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2691 FontOld
= NtGdiSelectFont(hDC
, Font
);
2693 if (pMenu
->cyMenu
== 0)
2695 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2698 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2700 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2702 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2703 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2704 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2705 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2707 if (pMenu
->cItems
== 0)
2709 NtGdiSelectFont(hDC
, FontOld
);
2710 return UserGetSystemMetrics(SM_CYMENU
);
2713 for (i
= 0; i
< pMenu
->cItems
; i
++)
2715 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2718 NtGdiSelectFont(hDC
, FontOld
);
2720 return pMenu
->cyMenu
;
2723 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2726 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2730 // No menu. Do not reserve any space
2736 return UserGetSystemMetrics(SM_CYMENU
);
2741 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2743 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2745 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2747 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2749 return lppop
->cyMenu
;
2753 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2757 /***********************************************************************
2760 * Popup menu initialization before WM_ENTERMENULOOP.
2762 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2765 PPOPUPMENU pPopupMenu
;
2767 LARGE_STRING WindowName
;
2768 UNICODE_STRING ClassName
;
2769 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2771 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2773 menu
->spwndNotify
= pWndOwner
;
2775 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2776 ex_style
= WS_EX_LAYOUTRTL
;
2778 ClassName
.Buffer
= WC_MENU
;
2779 ClassName
.Length
= 0;
2781 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2782 RtlZeroMemory(&Cs
, sizeof(Cs
));
2783 Cs
.style
= WS_POPUP
;
2784 Cs
.dwExStyle
= ex_style
;
2785 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2786 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2787 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2788 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2789 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2791 /* NOTE: In Windows, top menu popup is not owned. */
2792 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2794 if( !pWndCreated
) return FALSE
;
2797 // Setup pop up menu structure.
2799 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2801 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2803 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2804 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2805 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2807 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2808 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2809 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2810 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2811 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2813 if (pPopupMenu
->fRightButton
)
2814 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2816 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2818 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2819 menu
->fFlags
& MNF_RTOL
)
2821 pPopupMenu
->fDroppedLeft
= TRUE
;
2826 /***********************************************************************
2829 * Display a popup menu.
2831 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2832 INT x
, INT y
, INT xanchor
, INT yanchor
)
2838 USER_REFERENCE_ENTRY Ref
;
2840 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2841 pwndOwner
, menu
, id
, x
, y
, xanchor
, yanchor
);
2843 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2845 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2846 menu
->iItem
= NO_SELECTED_ITEM
;
2849 menu
->dwArrowsOn
= 0;
2850 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2852 /* adjust popup menu pos so that it fits within the desktop */
2854 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2855 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2857 /* FIXME: should use item rect */
2860 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2862 if (flags
& TPM_LAYOUTRTL
)
2863 flags
^= TPM_RIGHTALIGN
;
2865 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2866 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2868 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2869 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2871 if( x
+ width
> monitor
->rcMonitor
.right
)
2873 if( xanchor
&& x
>= width
- xanchor
)
2874 x
-= width
- xanchor
;
2876 if( x
+ width
> monitor
->rcMonitor
.right
)
2877 x
= monitor
->rcMonitor
.right
- width
;
2879 if( x
< monitor
->rcMonitor
.left
) x
= monitor
->rcMonitor
.left
;
2881 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2883 if( yanchor
&& y
>= height
+ yanchor
)
2884 y
-= height
+ yanchor
;
2886 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2887 y
= monitor
->rcMonitor
.bottom
- height
;
2889 if( y
< monitor
->rcMonitor
.top
) y
= monitor
->rcMonitor
.top
;
2891 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2895 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2900 top_popup
= menu
->hWnd
;
2901 top_popup_hmenu
= UserHMGetHandle(menu
);
2904 /* Display the window */
2905 UserRefObjectCo(pWnd
, &Ref
);
2906 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2908 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2910 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2911 UserDerefObjectCo(pWnd
);
2916 /***********************************************************************
2917 * MENU_EnsureMenuItemVisible
2919 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2921 USER_REFERENCE_ENTRY Ref
;
2922 if (lppop
->dwArrowsOn
)
2924 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2925 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2926 UINT nOldPos
= lppop
->iTop
;
2928 UINT arrow_bitmap_height
;
2929 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2931 IntGetClientRect(pWnd
, &rc
);
2933 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2935 rc
.top
+= arrow_bitmap_height
;
2936 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2938 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2939 UserRefObjectCo(pWnd
, &Ref
);
2940 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
2942 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
2943 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2944 MENU_DrawScrollArrows(lppop
, hdc
);
2945 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2947 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
2949 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
2950 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2951 MENU_DrawScrollArrows(lppop
, hdc
);
2952 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2954 UserDerefObjectCo(pWnd
);
2958 /***********************************************************************
2961 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
2962 BOOL sendMenuSelect
, PMENU topmenu
)
2967 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2969 if (!menu
|| !menu
->cItems
) return;
2971 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
2975 if (menu
->iItem
== wIndex
) return;
2977 if (menu
->fFlags
& MNF_POPUP
)
2978 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
2980 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2983 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
2984 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
2985 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
2988 NtGdiSelectFont( hdc
, ghMenuFont
);
2990 /* Clear previous highlighted item */
2991 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2993 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2994 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
2995 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
2999 /* Highlight new item (if any) */
3000 menu
->iItem
= wIndex
;
3001 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3003 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
3005 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
3006 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
3007 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
3008 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3012 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3013 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3014 ip
->fType
| ip
->fState
|
3015 (ip
->spSubMenu
? MF_POPUP
: 0) |
3016 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3018 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3021 else if (sendMenuSelect
)
3026 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3027 if (pos
!= NO_SELECTED_ITEM
)
3029 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3030 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3031 (ip
->spSubMenu
? MF_POPUP
: 0) |
3032 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3034 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3038 UserReleaseDC(pWnd
, hdc
, FALSE
);
3041 /***********************************************************************
3044 * Moves currently selected item according to the Offset parameter.
3045 * If there is no selection then it should select the last item if
3046 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3048 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3052 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3054 if ((!menu
) || (!menu
->rgItems
)) return;
3056 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3058 if ( menu
->cItems
== 1 )
3061 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3063 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3065 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3070 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3071 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3072 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3074 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3079 /***********************************************************************
3082 * Hide the sub-popup menus of this menu.
3084 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3085 BOOL SendMenuSelect
, UINT wFlags
)
3087 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3089 if ( Menu
&& top_popup
)
3093 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3095 Item
= &Menu
->rgItems
[Menu
->iItem
];
3096 if (!(Item
->spSubMenu
) ||
3097 !(Item
->fState
& MF_MOUSESELECT
)) return;
3098 Item
->fState
&= ~MF_MOUSESELECT
;
3103 if (Item
->spSubMenu
)
3106 if (!VerifyMenu(Item
->spSubMenu
)) return;
3107 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3108 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3109 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3110 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3111 co_UserDestroyWindow(pWnd
);
3113 /* Native returns handle to destroyed window */
3114 if (!(wFlags
& TPM_NONOTIFY
))
3116 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3117 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3120 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3121 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3123 Item
->spSubMenu
->hWnd
= NULL
;
3129 /***********************************************************************
3132 * Display the sub-menu of the selected item of this menu.
3133 * Return the handle of the submenu, or menu if no submenu to display.
3135 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3142 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3144 if (!Menu
) return Menu
;
3146 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3148 Item
= &Menu
->rgItems
[Menu
->iItem
];
3149 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3152 /* message must be sent before using item,
3153 because nearly everything may be changed by the application ! */
3155 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3156 if (!(Flags
& TPM_NONOTIFY
))
3158 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3159 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3160 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3163 Item
= &Menu
->rgItems
[Menu
->iItem
];
3164 //Rect = ItemInfo.Rect;
3165 Rect
.left
= Item
->xItem
;
3166 Rect
.top
= Item
->yItem
;
3167 Rect
.right
= Item
->cxItem
; // Do this for now......
3168 Rect
.bottom
= Item
->cyItem
;
3170 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3172 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3173 if (!(Item
->fState
& MF_HILITE
))
3175 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3176 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3178 NtGdiSelectFont(Dc
, ghMenuFont
);
3180 Item
->fState
|= MF_HILITE
;
3181 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3182 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3184 UserReleaseDC(pWnd
, Dc
, FALSE
);
3187 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3189 Item
->xItem
= Rect
.left
;
3190 Item
->yItem
= Rect
.top
;
3191 Item
->cxItem
= Rect
.right
; // Do this for now......
3192 Item
->cyItem
= Rect
.bottom
;
3194 Item
->fState
|= MF_MOUSESELECT
;
3196 if (IS_SYSTEM_MENU(Menu
))
3198 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3200 NC_GetSysPopupPos(pWnd
, &Rect
);
3201 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3202 Rect
.top
= Rect
.bottom
;
3203 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3204 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3208 IntGetWindowRect(pWnd
, &Rect
);
3209 if (Menu
->fFlags
& MNF_POPUP
)
3212 rc
.left
= Item
->xItem
;
3213 rc
.top
= Item
->yItem
;
3214 rc
.right
= Item
->cxItem
; // Do this for now......
3215 rc
.bottom
= Item
->cyItem
;
3217 MENU_AdjustMenuItemRect(Menu
, &rc
);
3219 /* The first item in the popup menu has to be at the
3220 same y position as the focused menu item */
3221 if(Flags
& TPM_LAYOUTRTL
)
3222 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3224 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3225 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3226 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3227 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3228 - UserGetSystemMetrics(SM_CYBORDER
);
3232 if(Flags
& TPM_LAYOUTRTL
)
3233 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3235 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3236 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3237 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3238 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3242 /* use default alignment for submenus */
3243 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3245 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3247 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3248 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3251 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3253 return Item
->spSubMenu
;
3256 /***********************************************************************
3257 * MenuExecFocusedItem
3259 * Execute a menu item (for instance when user pressed Enter).
3260 * Return the wID of the executed item. Otherwise, -1 indicating
3261 * that no menu item was executed, -2 if a popup is shown;
3262 * Have to receive the flags for the TrackPopupMenu options to avoid
3263 * sending unwanted message.
3266 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3270 TRACE("%p menu=%p\n", pmt
, Menu
);
3272 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3277 Item
= &Menu
->rgItems
[Menu
->iItem
];
3279 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3281 if (!(Item
->spSubMenu
))
3283 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3285 /* If TPM_RETURNCMD is set you return the id, but
3286 do not send a message to the owner */
3287 if (!(Flags
& TPM_RETURNCMD
))
3289 if (Menu
->fFlags
& MNF_SYSMENU
)
3291 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3292 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3296 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3298 if (dwStyle
& MNS_NOTIFYBYPOS
)
3299 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3301 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3309 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3316 /***********************************************************************
3317 * MenuSwitchTracking
3319 * Helper function for menu navigation routines.
3321 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3323 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3325 if ( pmt
->TopMenu
!= PtMenu
&&
3326 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3328 /* both are top level menus (system and menu-bar) */
3329 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3330 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3331 pmt
->TopMenu
= PtMenu
;
3335 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3338 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3341 /***********************************************************************
3344 * Return TRUE if we can go on with menu tracking.
3346 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3348 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3354 if (IS_SYSTEM_MENU(PtMenu
))
3356 item
= PtMenu
->rgItems
;
3360 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3365 if (PtMenu
->iItem
!= id
)
3366 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3368 /* If the popup menu is not already "popped" */
3369 if (!(item
->fState
& MF_MOUSESELECT
))
3371 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3376 /* Else the click was on the menu bar, finish the tracking */
3381 /***********************************************************************
3384 * Return the value of MenuExecFocusedItem if
3385 * the selected item was not a popup. Else open the popup.
3386 * A -1 return value indicates that we go on with menu tracking.
3389 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3391 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3398 if ( IS_SYSTEM_MENU(PtMenu
) )
3400 item
= PtMenu
->rgItems
;
3404 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3407 if (item
&& ( PtMenu
->iItem
== Id
))
3409 if (!(item
->spSubMenu
))
3411 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3412 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3413 return ExecutedMenuId
;
3416 /* If we are dealing with the menu bar */
3417 /* and this is a click on an already "popped" item: */
3418 /* Stop the menu tracking and close the opened submenus */
3419 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3424 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3426 PtMenu
->TimeToHide
= TRUE
;
3432 /***********************************************************************
3435 * Walks menu chain trying to find a menu pt maps to.
3437 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3442 if (!menu
) return NULL
;
3444 /* try subpopup first (if any) */
3445 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3447 pItem
= menu
->rgItems
;
3448 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3449 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3451 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3455 /* check the current window (avoiding WM_HITTEST) */
3458 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3459 INT ht
= GetNCHitEx(pWnd
, pt
);
3460 if ( menu
->fFlags
& MNF_POPUP
)
3462 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3464 else if (ht
== HTSYSMENU
)
3465 ret
= get_win_sys_menu(menu
->hWnd
);
3466 else if (ht
== HTMENU
)
3467 ret
= IntGetMenu( menu
->hWnd
);
3472 /***********************************************************************
3475 * Return TRUE if we can go on with menu tracking.
3477 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3479 UINT Index
= NO_SELECTED_ITEM
;
3483 if (IS_SYSTEM_MENU(PtMenu
))
3486 //// ReactOS only HACK: CORE-2338
3487 // Windows tracks mouse moves to the system menu but does not open it.
3488 // Only keyboard tracking can do that.
3490 TRACE("SystemMenu\n");
3491 return TRUE
; // Stay inside the Loop!
3494 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3497 if (Index
== NO_SELECTED_ITEM
)
3499 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3501 else if (PtMenu
->iItem
!= Index
)
3503 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3504 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3509 /***********************************************************************
3512 * Return the handle of the selected sub-popup menu (if any).
3514 static PMENU
MENU_GetSubPopup( PMENU menu
)
3518 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3520 item
= &menu
->rgItems
[menu
->iItem
];
3521 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3523 return item
->spSubMenu
;
3528 /***********************************************************************
3531 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3533 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3537 /* When skipping left, we need to do something special after the
3539 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3543 /* When skipping right, for the non-system menu, we need to
3544 handle the last non-special menu item (ie skip any window
3545 icons such as MDI maximize, restore or close) */
3546 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3548 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3549 while (i
< pmt
->TopMenu
->cItems
) {
3550 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3551 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3555 if (i
== pmt
->TopMenu
->cItems
) {
3559 /* When skipping right, we need to cater for the system menu */
3560 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3562 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3569 MDINEXTMENU NextMenu
;
3576 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3577 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3578 NextMenu
.hmenuNext
= NULL
;
3579 NextMenu
.hwndNext
= NULL
;
3580 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3582 TRACE("%p [%p] -> %p [%p]\n",
3583 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3585 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3587 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3588 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3590 /* switch to the menu bar */
3592 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3596 Id
= MenuTmp
->cItems
- 1;
3598 /* Skip backwards over any system predefined icons,
3599 eg. MDI close, restore etc icons */
3601 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3602 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3605 hNewMenu
= UserHMGetHandle(MenuTmp
);
3607 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3609 /* switch to the system menu */
3610 MenuTmp
= get_win_sys_menu(hNewWnd
);
3611 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3616 else /* application returned a new menu to switch to */
3618 hNewMenu
= NextMenu
.hmenuNext
;
3619 hNewWnd
= NextMenu
.hwndNext
;
3621 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3623 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3625 /* get the real system menu */
3626 MenuTmp
= get_win_sys_menu(hNewWnd
);
3627 hNewMenu
= UserHMGetHandle(MenuTmp
);
3629 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3631 /* FIXME: Not sure what to do here;
3632 * perhaps try to track NewMenu as a popup? */
3634 WARN(" -- got confused.\n");
3641 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3643 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3645 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3646 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3649 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3651 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3652 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3653 ///// Use thread pms!!!!
3654 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3655 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3656 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3657 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3660 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3661 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3668 /***********************************************************************
3671 * The idea is not to show the popup if the next input message is
3672 * going to hide it anyway.
3674 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3678 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3680 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3681 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3686 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3687 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3689 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3690 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3691 if( msg
.message
== WM_KEYDOWN
&&
3692 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3694 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3700 /* failures go through this */
3701 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3705 /***********************************************************************
3708 * Handle a VK_ESCAPE key event in a menu.
3710 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3712 BOOL EndMenu
= TRUE
;
3714 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3716 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3718 PMENU MenuPrev
, MenuTmp
;
3720 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3722 /* close topmost popup */
3723 while (MenuTmp
!= pmt
->CurrentMenu
)
3726 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3729 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3730 pmt
->CurrentMenu
= MenuPrev
;
3738 /***********************************************************************
3741 * Handle a VK_LEFT key event in a menu.
3743 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
, UINT msg
)
3745 PMENU MenuTmp
, MenuPrev
;
3748 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3750 /* Try to move 1 column left (if possible) */
3751 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3753 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3757 /* close topmost popup */
3758 while (MenuTmp
!= pmt
->CurrentMenu
)
3761 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3764 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3765 pmt
->CurrentMenu
= MenuPrev
;
3767 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3769 /* move menu bar selection if no more popups are left */
3771 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3772 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3774 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3776 /* A sublevel menu was displayed - display the next one
3777 * unless there is another displacement coming up */
3779 if (!MENU_SuspendPopup(pmt
, msg
))
3780 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3786 /***********************************************************************
3789 * Handle a VK_RIGHT key event in a menu.
3791 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
, UINT msg
)
3796 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3797 pmt
->CurrentMenu
, pmt
->TopMenu
);
3799 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3801 /* If already displaying a popup, try to display sub-popup */
3803 menutmp
= pmt
->CurrentMenu
;
3804 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3806 /* if subpopup was displayed then we are done */
3807 if (menutmp
!= pmt
->CurrentMenu
) return;
3810 /* Check to see if there's another column */
3811 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3813 TRACE("Going to %d.\n", NextCol
);
3814 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3818 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3820 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3822 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3823 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3830 /* try to move to the next item */
3831 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3832 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3834 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3836 if ( !MENU_SuspendPopup(pmt
, msg
) )
3837 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3842 /***********************************************************************
3845 * Menu tracking code.
3847 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3848 PWND pwnd
, const RECT
*lprect
)
3852 INT executedMenuId
= -1;
3856 BOOL enterIdleSent
= FALSE
;
3857 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3859 if (pti
!= pwnd
->head
.pti
)
3861 ERR("Not the same PTI!!!!\n");
3865 mt
.CurrentMenu
= pmenu
;
3871 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3872 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3873 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3875 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3877 if (wFlags
& TPM_BUTTONDOWN
)
3879 /* Get the result in order to start the tracking or not */
3880 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3881 fInsideMenuLoop
= fRemove
;
3884 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3886 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3888 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3889 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3890 co_UserSetCapture(NULL
); /* release the capture */
3894 capture_win
= IntGetCapture();
3896 while (fInsideMenuLoop
)
3898 BOOL ErrorExit
= FALSE
;
3899 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3902 /* we have to keep the message in the queue until it's
3903 * clear that menu loop is not over yet. */
3907 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3909 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3910 /* remove the message from the queue */
3911 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3915 /* ReactOS Checks */
3916 if (!VerifyWnd(mt
.OwnerWnd
) ||
3917 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3918 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3919 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3921 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3927 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3928 enterIdleSent
= TRUE
;
3929 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3931 co_IntWaitMessage(NULL
, 0, 0);
3935 if (ErrorExit
) break; // Gracefully dropout.
3937 /* check if EndMenu() tried to cancel us, by posting this message */
3938 if (msg
.message
== WM_CANCELMODE
)
3940 /* we are now out of the loop */
3941 fInsideMenuLoop
= FALSE
;
3943 /* remove the message from the queue */
3944 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3946 /* break out of internal loop, ala ESCAPE */
3952 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3953 enterIdleSent
=FALSE
;
3956 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3959 * Use the mouse coordinates in lParam instead of those in the MSG
3960 * struct to properly handle synthetic messages. They are already
3961 * in screen coordinates.
3963 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3964 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3966 /* Find a menu for this mouse event */
3967 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3971 /* no WM_NC... messages in captured state */
3973 case WM_RBUTTONDBLCLK
:
3974 case WM_RBUTTONDOWN
:
3975 if (!(wFlags
& TPM_RIGHTBUTTON
))
3977 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3981 case WM_LBUTTONDBLCLK
:
3982 case WM_LBUTTONDOWN
:
3983 /* If the message belongs to the menu, removes it from the queue */
3984 /* Else, end menu tracking */
3985 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3986 fInsideMenuLoop
= fRemove
;
3987 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3988 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3992 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3995 /* Check if a menu was selected by the mouse */
3998 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
4000 /* End the loop if executedMenuId is an item ID */
4001 /* or if the job was done (executedMenuId = 0). */
4002 fRemove
= (executedMenuId
!= -1);
4003 fInsideMenuLoop
= !fRemove
;
4005 /* No menu was selected by the mouse */
4006 /* if the function was called by TrackPopupMenu, continue
4007 with the menu tracking. If not, stop it */
4009 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4014 /* the selected menu item must be changed every time */
4015 /* the mouse moves. */
4018 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4020 } /* switch(msg.message) - mouse */
4022 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4024 fRemove
= TRUE
; /* Keyboard messages are always removed */
4033 fInsideMenuLoop
= FALSE
;
4038 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4039 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4043 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4044 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4045 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4046 else /* otherwise try to move selection */
4047 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4051 MENU_KeyLeft( &mt
, wFlags
, msg
.message
);
4055 MENU_KeyRight( &mt
, wFlags
, msg
.message
);
4059 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4065 hi
.cbSize
= sizeof(HELPINFO
);
4066 hi
.iContextType
= HELPINFO_MENUITEM
;
4067 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4070 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4071 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4072 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4073 hi
.MousePos
= msg
.pt
;
4074 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4079 IntTranslateKbdMessage(&msg
, 0);
4082 break; /* WM_KEYDOWN */
4090 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4092 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4093 fEndMenu
= (executedMenuId
!= -2);
4094 fInsideMenuLoop
= !fEndMenu
;
4098 /* Hack to avoid control chars. */
4099 /* We will find a better way real soon... */
4100 if (msg
.wParam
< 32) break;
4102 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4104 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4105 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4108 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4109 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4110 fEndMenu
= (executedMenuId
!= -2);
4111 fInsideMenuLoop
= !fEndMenu
;
4115 } /* switch(msg.message) - kbd */
4119 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4120 IntDispatchMessage( &msg
);
4124 if (fInsideMenuLoop
) fRemove
= TRUE
;
4126 /* finally remove message from the queue */
4128 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4129 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4130 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4133 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4134 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4135 co_UserSetCapture(NULL
); /* release the capture */
4137 /* If dropdown is still painted and the close box is clicked on
4138 then the menu will be destroyed as part of the DispatchMessage above.
4139 This will then invalidate the menu handle in mt.hTopMenu. We should
4140 check for this first. */
4141 if ( VerifyMenu( mt
.TopMenu
) )
4143 if (VerifyWnd(mt
.OwnerWnd
))
4145 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4147 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4149 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4152 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4154 co_UserDestroyWindow(pwndTM
);
4156 mt
.TopMenu
->hWnd
= NULL
;
4158 if (!(wFlags
& TPM_NONOTIFY
))
4160 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4161 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4164 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4165 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4168 /* Reset the variable for hiding menu */
4169 mt
.TopMenu
->TimeToHide
= FALSE
;
4172 EngSetLastError( ERROR_SUCCESS
);
4173 /* The return value is only used by TrackPopupMenu */
4174 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4175 if (executedMenuId
== -1) executedMenuId
= 0;
4176 return executedMenuId
;
4179 /***********************************************************************
4182 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4185 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4187 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4189 co_UserHideCaret(0);
4191 /* This makes the menus of applications built with Delphi work.
4192 * It also enables menus to be displayed in more than one window,
4193 * but there are some bugs left that need to be fixed in this case.
4197 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4201 top_popup
= Menu
->hWnd
;
4202 top_popup_hmenu
= UserHMGetHandle(Menu
);
4205 fInsideMenuLoop
= TRUE
;
4208 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4209 if (!(wFlags
& TPM_NONOTIFY
))
4211 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4215 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4217 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4218 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4219 co_UserSetCapture(capture_win
); // 2
4220 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4222 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4224 if (!(wFlags
& TPM_NONOTIFY
))
4226 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4227 /* If an app changed/recreated menu bar entries in WM_INITMENU
4228 * menu sizes will be recalculated once the menu created/shown.
4232 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4234 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4239 /***********************************************************************
4242 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4244 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4246 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4248 if (!(wFlags
& TPM_NONOTIFY
))
4249 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4251 co_UserShowCaret(0);
4254 top_popup_hmenu
= NULL
;
4259 /***********************************************************************
4260 * MenuTrackMouseMenuBar
4262 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4264 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4266 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) ); // See 74276 and CORE-12801
4267 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4269 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4271 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4272 if (VerifyMenu(pMenu
))
4274 /* map point to parent client coordinates */
4275 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4276 if (Parent
!= UserGetDesktopWindow())
4278 IntScreenToClient(Parent
, &pt
);
4281 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4282 /* fetch the window menu again, it may have changed */
4283 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4284 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4285 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4289 /***********************************************************************
4290 * MenuTrackKbdMenuBar
4292 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4294 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4296 UINT uItem
= NO_SELECTED_ITEM
;
4298 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4300 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4302 /* find window that has a menu */
4304 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4305 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4307 /* check if we have to track a system menu */
4309 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4310 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4312 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4313 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4315 wParam
|= HTSYSMENU
; /* prevent item lookup */
4318 if (!VerifyMenu( TrackMenu
)) return;
4320 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4322 /* fetch the window menu again, it may have changed */
4323 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4325 if( wChar
&& wChar
!= ' ' )
4327 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4328 if ( uItem
>= (UINT
)(-2) )
4330 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4331 /* schedule end of menu tracking */
4332 wFlags
|= TF_ENDMENU
;
4337 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4339 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4341 if( uItem
== NO_SELECTED_ITEM
)
4342 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4344 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4348 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4349 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4352 /**********************************************************************
4353 * TrackPopupMenuEx (USER32.@)
4355 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4356 PWND pWnd
, LPTPMPARAMS lpTpm
)
4359 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4361 if (pti
!= pWnd
->head
.pti
)
4363 ERR("Must be the same pti!\n");
4367 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4368 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4369 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4371 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4373 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4377 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4379 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4381 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4382 if (!(wFlags
& TPM_NONOTIFY
))
4384 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4387 if (menu
->fFlags
& MNF_SYSMENU
)
4388 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4390 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4391 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4392 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4395 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4396 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4397 co_UserSetCapture(NULL
); /* release the capture */
4400 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4404 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4405 if (pwndM
) // wine hack around this with their destroy function.
4407 if (!(pWnd
->state
& WNDS_DESTROYED
))
4408 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4412 if (!(wFlags
& TPM_NONOTIFY
))
4414 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4415 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4433 PPOPUPMENU pPopupMenu
;
4437 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4443 if (Message
!= WM_NCCREATE
)
4445 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4448 Wnd
->fnid
= FNID_MENU
;
4449 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4450 if (pPopupMenu
== NULL
)
4454 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4455 pPopupMenu
->spwndPopupMenu
= Wnd
;
4456 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4457 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4463 if (Wnd
->fnid
!= FNID_MENU
)
4465 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4468 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4476 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4477 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4481 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4482 *lResult
= MA_NOACTIVATE
;
4488 IntBeginPaint(Wnd
, &ps
);
4489 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4490 IntEndPaint(Wnd
, &ps
);
4494 case WM_PRINTCLIENT
:
4496 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4505 /* zero out global pointer in case resident popup window was destroyed. */
4508 if (UserHMGetHandle(Wnd
) == top_popup
)
4511 top_popup_hmenu
= NULL
;
4516 ERR("No Window Pop Up!\n");
4522 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4523 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4524 Wnd
->fnid
= FNID_DESTROY
;
4528 case MM_SETMENUHANDLE
: // wine'isms
4531 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4534 ERR("Bad Menu Handle\n");
4537 pPopupMenu
->spmenu
= pmenu
;
4541 case MM_GETMENUHANDLE
: // wine'isms
4543 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4547 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4549 ERR("Someone is passing unknown menu messages %d\n",Message
);
4551 TRACE("PMWP to IDWP %d\n",Message
);
4552 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4560 IntHiliteMenuItem(PWND WindowObject
,
4566 UINT uItem
= uItemHilite
;
4568 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4570 if (uHilite
& MF_HILITE
)
4572 MenuItem
->fState
|= MF_HILITE
;
4576 MenuItem
->fState
&= ~MF_HILITE
;
4578 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4579 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4580 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4582 return TRUE
; // Always returns true!!!!
4586 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4590 DWORD dwExStyle
= 0;
4591 BOOLEAN retValue
= TRUE
;
4593 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4595 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4597 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4599 dwStyle
= pWindowObject
->style
;
4600 dwExStyle
= pWindowObject
->ExStyle
;
4602 bti
->rcTitleBar
.top
= 0;
4603 bti
->rcTitleBar
.left
= 0;
4604 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4605 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4607 /* Is it iconiced ? */
4608 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4610 /* Remove frame from rectangle */
4611 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4613 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4614 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4616 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4618 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4619 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4621 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4623 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4624 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4627 /* We have additional border information if the window
4628 * is a child (but not an MDI child) */
4629 if ( (dwStyle
& WS_CHILD
) &&
4630 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4632 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4634 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4635 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4638 if (dwExStyle
& WS_EX_STATICEDGE
)
4640 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4641 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4646 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4647 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4648 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4650 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4651 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4653 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4654 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4658 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4659 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4660 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4663 if (dwStyle
& WS_CAPTION
)
4665 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4666 if (dwStyle
& WS_SYSMENU
)
4668 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4670 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4671 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4675 if (!(dwStyle
& WS_MINIMIZEBOX
))
4677 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4679 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4681 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4685 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4687 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4689 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4691 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4696 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4697 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4698 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4699 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4704 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4709 EngSetLastError(ERROR_INVALID_PARAMETER
);
4721 LPCMENUITEMINFOW UnsafeItemInfo
,
4722 PUNICODE_STRING lpstr
)
4725 ROSMENUITEMINFO ItemInfo
;
4727 /* Try to copy the whole MENUITEMINFOW structure */
4728 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4729 if (NT_SUCCESS(Status
))
4731 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4732 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4734 EngSetLastError(ERROR_INVALID_PARAMETER
);
4737 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4740 /* Try to copy without last field (not present in older versions) */
4741 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4742 if (NT_SUCCESS(Status
))
4744 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4746 EngSetLastError(ERROR_INVALID_PARAMETER
);
4749 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4750 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4753 SetLastNtError(Status
);
4757 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4762 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4767 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4769 if (pItem
->spSubMenu
)
4771 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4774 return (pItem
->fType
| pItem
->fState
);
4777 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4782 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4787 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4789 if (pItem
->spSubMenu
)
4791 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4797 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4799 PMENU menu
, pSubTarget
;
4801 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4802 return NO_SELECTED_ITEM
;
4804 pSubTarget
= UserGetMenuObject(hSubTarget
);
4806 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4808 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4814 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4816 PWINSTATION_OBJECT WinStaObject
;
4820 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4822 if (gpepCSRSS
!= CurrentProcess
)
4825 * gpepCSRSS does not have a Win32WindowStation
4828 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4834 if (!NT_SUCCESS(Status
))
4836 ERR("Validation of window station handle (%p) failed\n",
4837 CurrentProcess
->Win32WindowStation
);
4838 SetLastNtError(Status
);
4841 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4842 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4844 ERR("Desktop Window Station does not match Process one!\n");
4846 ObDereferenceObject(WinStaObject
);
4850 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4853 if (Menu
) UserDereferenceObject(Menu
);
4854 return (HMENU
)Handle
;
4862 PROSMENUITEMINFO ItemInfo
,
4864 PUNICODE_STRING lpstr
)
4869 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4871 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4876 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4880 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4890 PROSMENUITEMINFO UnsafeItemInfo
,
4892 PUNICODE_STRING lpstr
)
4895 ROSMENUITEMINFO ItemInfo
;
4900 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4901 if (! NT_SUCCESS(Status
))
4903 SetLastNtError(Status
);
4906 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4907 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4908 Size
!= sizeof(ROSMENUITEMINFO
) )
4910 EngSetLastError(ERROR_INVALID_PARAMETER
);
4913 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4914 if (! NT_SUCCESS(Status
))
4916 SetLastNtError(Status
);
4919 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4921 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4922 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4924 EngSetLastError(ERROR_INVALID_PARAMETER
);
4928 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4930 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4931 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4934 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4940 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4944 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4947 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4948 if (! NT_SUCCESS(Status
))
4950 SetLastNtError(Status
);
4962 PROSMENUINFO UnsafeMenuInfo
,
4968 ROSMENUINFO MenuInfo
;
4970 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4971 if (! NT_SUCCESS(Status
))
4973 SetLastNtError(Status
);
4976 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4978 EngSetLastError(ERROR_INVALID_PARAMETER
);
4981 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4982 if (! NT_SUCCESS(Status
))
4984 SetLastNtError(Status
);
4991 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4996 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4999 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
5000 if (! NT_SUCCESS(Status
))
5002 SetLastNtError(Status
);
5022 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5024 Rect
->left
= MenuItem
->xItem
;
5025 Rect
->top
= MenuItem
->yItem
;
5026 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5027 Rect
->bottom
= MenuItem
->cyItem
;
5031 ERR("Failed Item Lookup! %u\n", uItem
);
5037 HWND hWnd
= Menu
->hWnd
;
5038 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5041 if (Menu
->fFlags
& MNF_POPUP
)
5043 XMove
= pWnd
->rcClient
.left
;
5044 YMove
= pWnd
->rcClient
.top
;
5048 XMove
= pWnd
->rcWindow
.left
;
5049 YMove
= pWnd
->rcWindow
.top
;
5052 Rect
->left
+= XMove
;
5054 Rect
->right
+= XMove
;
5055 Rect
->bottom
+= YMove
;
5060 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5062 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5063 HMENU hSysMenu
, hNewMenu
= NULL
;
5064 ROSMENUITEMINFO ItemInfoSet
= {0};
5065 ROSMENUITEMINFO ItemInfo
= {0};
5066 UNICODE_STRING MenuName
;
5068 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5069 if (NULL
== hSysMenu
)
5073 SysMenu
= UserGetMenuObject(hSysMenu
);
5074 if (NULL
== SysMenu
)
5076 UserDestroyMenu(hSysMenu
);
5080 SysMenu
->fFlags
|= MNF_SYSMENU
;
5081 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5085 //hNewMenu = co_IntLoadSysMenuTemplate();
5086 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5088 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5089 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5093 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5094 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5095 //ERR("%wZ\n",&MenuName);
5100 IntDestroyMenuObject(SysMenu
, FALSE
);
5103 Menu
= UserGetMenuObject(hNewMenu
);
5106 IntDestroyMenuObject(SysMenu
, FALSE
);
5110 // Do the rest in here.
5112 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5114 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5115 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5116 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5117 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5118 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5119 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5120 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5121 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5122 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5123 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5125 NewMenu
= IntCloneMenu(Menu
);
5126 if (NewMenu
== NULL
)
5128 IntDestroyMenuObject(Menu
, FALSE
);
5129 IntDestroyMenuObject(SysMenu
, FALSE
);
5133 IntReleaseMenuObject(NewMenu
);
5134 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5136 IntDestroyMenuObject(Menu
, FALSE
);
5144 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5146 if (Window
->pcls
->style
& CS_NOCLOSE
)
5147 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5149 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5150 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5151 ItemInfo
.fType
= MF_POPUP
;
5152 ItemInfo
.fState
= MFS_ENABLED
;
5153 ItemInfo
.dwTypeData
= NULL
;
5155 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5156 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5160 ERR("failed to load system menu!\n");
5165 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5171 if (Window
->SystemMenu
)
5173 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5174 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5176 IntDestroyMenuObject(Menu
, TRUE
);
5177 Window
->SystemMenu
= NULL
;
5183 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5184 if ((!Menu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5186 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5187 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5191 if (Window
->SystemMenu
)
5193 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5194 /* Store the dummy sysmenu handle to facilitate the refresh */
5195 /* of the close button if the SC_CLOSE item change */
5196 Menu
= UserGetMenuObject(hMenu
);
5199 Menu
->spwndNotify
= Window
;
5200 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5208 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5212 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5214 if (Window
->SystemMenu
)
5216 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5219 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5220 IntDestroyMenuObject(OldMenu
, TRUE
);
5224 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5226 { // Use spmenuSys too!
5227 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5230 Window
->SystemMenu
= NULL
;
5232 if (Menu
&& Window
!= Menu
->spwndNotify
)
5234 Menu
->spwndNotify
= Window
;
5246 PMENU OldMenu
, NewMenu
= NULL
;
5248 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5250 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5251 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5255 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5263 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5264 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5273 NewMenu
= IntGetMenuObject(Menu
);
5274 if (NULL
== NewMenu
)
5276 if (NULL
!= OldMenu
)
5278 IntReleaseMenuObject(OldMenu
);
5280 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5283 if (NULL
!= NewMenu
->hWnd
)
5285 /* Can't use the same menu for two windows */
5286 if (NULL
!= OldMenu
)
5288 IntReleaseMenuObject(OldMenu
);
5290 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5296 Wnd
->IDMenu
= (UINT_PTR
) Menu
;
5297 if (NULL
!= NewMenu
)
5299 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5300 IntReleaseMenuObject(NewMenu
);
5302 if (NULL
!= OldMenu
)
5304 OldMenu
->hWnd
= NULL
;
5305 IntReleaseMenuObject(OldMenu
);
5312 /* FUNCTIONS *****************************************************************/
5317 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5332 UserEnterExclusive();
5334 if(!(Window
= UserGetWindowObject(hwnd
)))
5336 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5341 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5348 Rect
.left
= leftBorder
;
5349 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5353 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5355 UserReleaseDC( 0, hdc
, FALSE
);
5366 NtUserCheckMenuItem(
5372 DECLARE_RETURN(DWORD
);
5374 TRACE("Enter NtUserCheckMenuItem\n");
5375 UserEnterExclusive();
5377 if(!(Menu
= UserGetMenuObject(hMenu
)))
5382 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5385 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5400 DECLARE_RETURN(BOOL
);
5402 TRACE("Enter NtUserDeleteMenu\n");
5403 UserEnterExclusive();
5405 if(!(Menu
= UserGetMenuObject(hMenu
)))
5410 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5413 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5419 * NtUserGetSystemMenu
5421 * The NtUserGetSystemMenu function allows the application to access the
5422 * window menu (also known as the system menu or the control menu) for
5423 * copying and modifying.
5427 * Handle to the window that will own a copy of the window menu.
5429 * Specifies the action to be taken. If this parameter is FALSE,
5430 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5431 * currently in use. The copy is initially identical to the window menu
5432 * but it can be modified.
5433 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5434 * to the default state. The previous window menu, if any, is destroyed.
5437 * If the bRevert parameter is FALSE, the return value is a handle to a
5438 * copy of the window menu. If the bRevert parameter is TRUE, the return
5446 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5450 DECLARE_RETURN(HMENU
);
5452 TRACE("Enter NtUserGetSystemMenu\n");
5455 if (!(Window
= UserGetWindowObject(hWnd
)))
5460 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5465 RETURN(Menu
->head
.h
);
5468 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5474 * NtUserSetSystemMenu
5481 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5483 BOOL Result
= FALSE
;
5486 DECLARE_RETURN(BOOL
);
5488 TRACE("Enter NtUserSetSystemMenu\n");
5489 UserEnterExclusive();
5491 if (!(Window
= UserGetWindowObject(hWnd
)))
5499 * Assign new menu handle and Up the Lock Count.
5501 if (!(Menu
= IntGetMenuObject(hMenu
)))
5506 Result
= IntSetSystemMenu(Window
, Menu
);
5509 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5514 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5523 NtUserGetTitleBarInfo(
5528 TITLEBARINFO bartitleinfo
;
5529 DECLARE_RETURN(BOOLEAN
);
5530 BOOLEAN retValue
= TRUE
;
5532 TRACE("Enter NtUserGetTitleBarInfo\n");
5533 UserEnterExclusive();
5535 /* Vaildate the windows handle */
5536 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5538 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5544 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5545 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5546 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5550 /* Fail copy the data */
5551 EngSetLastError(ERROR_INVALID_PARAMETER
);
5556 /* Get the tile bar info */
5559 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5564 /* Copy our buffer to user mode buffer bti */
5565 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5566 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5568 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5570 /* Fail copy the data */
5571 EngSetLastError(ERROR_INVALID_PARAMETER
);
5581 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5589 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5592 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5594 if(!(Menu
= UserGetMenuObject(hMenu
)))
5599 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5601 EngSetLastError(ERROR_ACCESS_DENIED
);
5604 return IntDestroyMenuObject(Menu
, FALSE
);
5615 DECLARE_RETURN(BOOL
);
5617 TRACE("Enter NtUserDestroyMenu\n");
5618 UserEnterExclusive();
5620 if(!(Menu
= UserGetMenuObject(hMenu
)))
5624 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5626 EngSetLastError(ERROR_ACCESS_DENIED
);
5629 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5632 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5641 NtUserEnableMenuItem(
5647 DECLARE_RETURN(UINT
);
5649 TRACE("Enter NtUserEnableMenuItem\n");
5650 UserEnterExclusive();
5652 if(!(Menu
= UserGetMenuObject(hMenu
)))
5657 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5660 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5672 TRACE("Enter NtUserEndMenu\n");
5673 UserEnterExclusive();
5674 /* if ( gptiCurrent->pMenuState &&
5675 gptiCurrent->pMenuState->pGlobalPopupMenu )
5677 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5680 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5683 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5685 if (fInsideMenuLoop
&& top_popup
)
5687 fInsideMenuLoop
= FALSE
;
5688 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5691 TRACE("Leave NtUserEndMenu\n");
5699 NtUserGetMenuBarInfo(
5709 PPOPUPMENU pPopupMenu
;
5710 USER_REFERENCE_ENTRY Ref
;
5711 NTSTATUS Status
= STATUS_SUCCESS
;
5713 DECLARE_RETURN(BOOL
);
5715 TRACE("Enter NtUserGetMenuBarInfo\n");
5718 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5720 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5724 UserRefObjectCo(pWnd
, &Ref
);
5726 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5728 kmbi
.hwndMenu
= NULL
;
5729 kmbi
.fBarFocused
= FALSE
;
5730 kmbi
.fFocused
= FALSE
;
5735 if (!pWnd
->pcls
->fnid
)
5737 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5739 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5740 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5743 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5744 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5745 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5746 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5748 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5750 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5755 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5756 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5757 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5760 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5761 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5762 hMenu
= UserHMGetHandle(Menu
);
5773 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5774 kmbi
.cbSize
= pmbi
->cbSize
;
5776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5782 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5784 EngSetLastError(ERROR_INVALID_PARAMETER
);
5788 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5792 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5797 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5798 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5799 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5800 TRACE("idItem a 0 %d\n",Ret
);
5804 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5805 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5809 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5810 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5813 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5814 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5816 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5821 kmbi
.fFocused
= kmbi
.fBarFocused
;
5826 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5827 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5829 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5831 Status
= _SEH2_GetExceptionCode();
5835 if (!NT_SUCCESS(Status
))
5837 SetLastNtError(Status
);
5844 if (pWnd
) UserDerefObjectCo(pWnd
);
5845 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5858 PMENU Menu
, SubMenu
;
5861 DECLARE_RETURN(UINT
);
5863 TRACE("Enter NtUserGetMenuIndex\n");
5866 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5867 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5870 MenuItem
= Menu
->rgItems
;
5871 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5873 if (MenuItem
->spSubMenu
== SubMenu
)
5874 RETURN(MenuItem
->wID
);
5879 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5888 NtUserGetMenuItemRect(
5899 NTSTATUS Status
= STATUS_SUCCESS
;
5900 DECLARE_RETURN(BOOL
);
5902 TRACE("Enter NtUserGetMenuItemRect\n");
5905 if (!(Menu
= UserGetMenuObject(hMenu
)))
5910 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5912 Rect
.left
= MenuItem
->xItem
;
5913 Rect
.top
= MenuItem
->yItem
;
5914 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5915 Rect
.bottom
= MenuItem
->cyItem
;
5925 if (lprcItem
== NULL
) RETURN( FALSE
);
5927 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5929 if (Menu
->fFlags
& MNF_POPUP
)
5931 XMove
= ReferenceWnd
->rcClient
.left
;
5932 YMove
= ReferenceWnd
->rcClient
.top
;
5936 XMove
= ReferenceWnd
->rcWindow
.left
;
5937 YMove
= ReferenceWnd
->rcWindow
.top
;
5942 Rect
.right
+= XMove
;
5943 Rect
.bottom
+= YMove
;
5947 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5949 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5951 Status
= _SEH2_GetExceptionCode();
5955 if (!NT_SUCCESS(Status
))
5957 SetLastNtError(Status
);
5963 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5972 NtUserHiliteMenuItem(
5980 DECLARE_RETURN(BOOLEAN
);
5982 TRACE("Enter NtUserHiliteMenuItem\n");
5983 UserEnterExclusive();
5985 if(!(Window
= UserGetWindowObject(hWnd
)))
5987 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5991 if(!(Menu
= UserGetMenuObject(hMenu
)))
5993 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5997 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
6000 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
6010 NtUserDrawMenuBarTemp(
6020 NTSTATUS Status
= STATUS_SUCCESS
;
6021 DECLARE_RETURN(DWORD
);
6023 ERR("Enter NtUserDrawMenuBarTemp\n");
6024 UserEnterExclusive();
6026 if(!(Window
= UserGetWindowObject(hWnd
)))
6028 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6032 if(!(Menu
= UserGetMenuObject(hMenu
)))
6034 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6040 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6041 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6043 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6045 Status
= _SEH2_GetExceptionCode();
6049 if (Status
!= STATUS_SUCCESS
)
6051 SetLastNtError(Status
);
6055 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6058 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6067 NtUserMenuItemFromPoint(
6077 DECLARE_RETURN(int);
6079 TRACE("Enter NtUserMenuItemFromPoint\n");
6080 UserEnterExclusive();
6082 if (!(Menu
= UserGetMenuObject(hMenu
)))
6087 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6092 X
-= Window
->rcWindow
.left
;
6093 Y
-= Window
->rcWindow
.top
;
6096 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6100 Rect
.left
= mi
->xItem
;
6101 Rect
.top
= mi
->yItem
;
6102 Rect
.right
= mi
->cxItem
;
6103 Rect
.bottom
= mi
->cyItem
;
6105 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6107 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6113 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6116 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6136 UserEnterExclusive();
6138 if(!(Window
= UserGetWindowObject(hWnd
)))
6140 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6145 Rect
.left
= leftBorder
;
6146 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6150 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6167 DECLARE_RETURN(BOOL
);
6169 TRACE("Enter NtUserRemoveMenu\n");
6170 UserEnterExclusive();
6172 if(!(Menu
= UserGetMenuObject(hMenu
)))
6177 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6180 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6197 DECLARE_RETURN(BOOL
);
6199 TRACE("Enter NtUserSetMenu\n");
6200 UserEnterExclusive();
6202 if (!(Window
= UserGetWindowObject(hWnd
)))
6207 if (!IntSetMenu(Window
, Menu
, &Changed
))
6212 // Not minimized and please repaint!!!
6213 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6215 USER_REFERENCE_ENTRY Ref
;
6216 UserRefObjectCo(Window
, &Ref
);
6217 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6218 UserDerefObjectCo(Window
);
6224 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6233 NtUserSetMenuContextHelpId(
6235 DWORD dwContextHelpId
)
6238 DECLARE_RETURN(BOOL
);
6240 TRACE("Enter NtUserSetMenuContextHelpId\n");
6241 UserEnterExclusive();
6243 if(!(Menu
= UserGetMenuObject(hMenu
)))
6248 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6251 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6260 NtUserSetMenuDefaultItem(
6266 DECLARE_RETURN(BOOL
);
6268 TRACE("Enter NtUserSetMenuDefaultItem\n");
6269 UserEnterExclusive();
6271 if(!(Menu
= UserGetMenuObject(hMenu
)))
6276 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6279 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6288 NtUserSetMenuFlagRtoL(
6292 DECLARE_RETURN(BOOL
);
6294 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6295 UserEnterExclusive();
6297 if(!(Menu
= UserGetMenuObject(hMenu
)))
6302 RETURN(IntSetMenuFlagRtoL(Menu
));
6305 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6314 NtUserThunkedMenuInfo(
6319 DECLARE_RETURN(BOOL
);
6321 TRACE("Enter NtUserThunkedMenuInfo\n");
6322 UserEnterExclusive();
6324 if (!(Menu
= UserGetMenuObject(hMenu
)))
6329 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6332 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6341 NtUserThunkedMenuItemInfo(
6346 LPMENUITEMINFOW lpmii
,
6347 PUNICODE_STRING lpszCaption
)
6351 UNICODE_STRING lstrCaption
;
6352 DECLARE_RETURN(BOOL
);
6354 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6355 UserEnterExclusive();
6357 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6358 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6360 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6362 if (!(Menu
= UserGetMenuObject(hMenu
)))
6367 /* Check if we got a Caption */
6368 if (lpszCaption
&& lpszCaption
->Buffer
)
6370 /* Copy the string to kernel mode */
6371 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6374 if (!NT_SUCCESS(Status
))
6376 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6377 SetLastNtError(Status
);
6382 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6384 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6387 if (lstrCaption
.Buffer
)
6389 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6392 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6401 NtUserTrackPopupMenuEx(
6413 USER_REFERENCE_ENTRY Ref
;
6415 TRACE("Enter NtUserTrackPopupMenuEx\n");
6416 UserEnterExclusive();
6417 /* Parameter check */
6418 if (!(menu
= UserGetMenuObject( hMenu
)))
6420 ERR("TPME : Invalid Menu handle.\n");
6421 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6425 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6427 ERR("TPME : Invalid Window handle.\n");
6435 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6440 _SEH2_YIELD(goto Exit
);
6444 UserRefObjectCo(pWnd
, &Ref
);
6445 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6446 UserDerefObjectCo(pWnd
);
6449 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);