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 Source
.Length
= Source
.MaximumLength
= lpmii
->cch
* sizeof(WCHAR
);
1174 Source
.Buffer
= lpmii
->dwTypeData
;
1176 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1177 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1179 MenuItem
->lpstr
.Length
= 0;
1180 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1181 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1182 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1184 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1185 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1190 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1191 !MenuItem
->Xlpstr
&&
1192 !lpmii
->dwTypeData
&&
1193 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1195 MenuItem
->fType
|= MFT_SEPARATOR
;
1197 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1199 MenuItem
->xItem
= lpmii
->Rect
.left
;
1200 MenuItem
->yItem
= lpmii
->Rect
.top
;
1201 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1202 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1203 MenuItem
->dxTab
= lpmii
->dxTab
;
1204 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1205 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1206 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1214 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1219 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1221 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1223 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1225 /* If the close item in the system menu change update the close button */
1228 switch (MenuItem
->wID
) // More than just close.
1236 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1238 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1240 /* Refresh the frame to reflect the change */
1241 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1243 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1246 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1256 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1261 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1263 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1265 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1271 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1274 PITEM MenuItem
= MenuObject
->rgItems
;
1276 if (!MenuItem
) return FALSE
;
1278 /* reset all default-item flags */
1279 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1281 MenuItem
->fState
&= ~MFS_DEFAULT
;
1284 /* no default item */
1285 if(uItem
== (UINT
)-1)
1289 MenuItem
= MenuObject
->rgItems
;
1292 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1293 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1298 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1300 if (MenuItem
->wID
== uItem
)
1302 MenuItem
->fState
|= MFS_DEFAULT
;
1312 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1315 PITEM MenuItem
= MenuObject
->rgItems
;
1318 if (!MenuItem
) return -1;
1320 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1323 if (i
>= MenuObject
->cItems
) return -1;
1326 /* default: don't return disabled items */
1327 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1329 /* search rekursiv when needed */
1330 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1334 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1336 if ( -1 != ret
) return ret
;
1338 /* when item not found in submenu, return the popup item */
1340 return ( fByPos
) ? i
: MenuItem
->wID
;
1350 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1351 return pItem
->spSubMenu
;
1354 /***********************************************************************
1355 * MenuInitSysMenuPopup
1357 * Grey the appropriate items in System menu.
1359 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1364 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1365 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1366 gray
= ((style
& WS_MAXIMIZE
) != 0);
1367 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1368 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1369 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1370 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1371 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1372 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1373 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1374 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1376 /* The menu item must keep its state if it's disabled */
1378 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1380 /* Set default menu item */
1381 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1382 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1383 else DefItem
= SC_CLOSE
;
1385 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1389 /***********************************************************************
1390 * MenuDrawPopupGlyph
1392 * Draws popup magic glyphs (can be found in system menu).
1394 static void FASTCALL
1395 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1398 HFONT hFont
, hOldFont
;
1404 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1407 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1410 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1413 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1417 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1420 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1421 RECTL_vInflateRect(r
, -2, -2);
1422 lf
.lfHeight
= r
->bottom
- r
->top
;
1424 lf
.lfWeight
= FW_NORMAL
;
1425 lf
.lfCharSet
= DEFAULT_CHARSET
;
1426 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1427 hFont
= GreCreateFontIndirectW(&lf
);
1428 /* save font and text color */
1429 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1430 clrsave
= GreGetTextColor(dc
);
1431 bkmode
= GreGetBkMode(dc
);
1432 /* set color and drawing mode */
1433 IntGdiSetBkMode(dc
, TRANSPARENT
);
1439 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1440 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1443 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1444 /* draw selected symbol */
1445 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1446 /* restore previous settings */
1447 IntGdiSetTextColor(dc
, clrsave
);
1448 NtGdiSelectFont(dc
, hOldFont
);
1449 IntGdiSetBkMode(dc
, bkmode
);
1450 GreDeleteObject(hFont
);
1453 /***********************************************************************
1454 * MENU_AdjustMenuItemRect
1456 * Adjust menu item rectangle according to scrolling state.
1459 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1461 if (menu
->dwArrowsOn
)
1463 UINT arrow_bitmap_height
;
1464 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1465 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1466 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1470 /***********************************************************************
1471 * MENU_FindItemByCoords
1473 * Find the item at the specified coordinates (screen coords). Does
1474 * not work for child windows and therefore should not be called for
1475 * an arbitrary system menu.
1477 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1482 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1484 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1485 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1486 pt
.x
= rect
.right
- 1 - pt
.x
;
1490 item
= menu
->rgItems
;
1491 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1493 //rect = item->rect;
1494 rect
.left
= item
->xItem
;
1495 rect
.top
= item
->yItem
;
1496 rect
.right
= item
->cxItem
; // Do this for now......
1497 rect
.bottom
= item
->cyItem
;
1499 MENU_AdjustMenuItemRect(menu
, &rect
);
1500 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1509 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1511 MENU
*menu
= UserGetMenuObject(hMenu
);
1514 /*FIXME: Do we have to handle hWnd here? */
1515 if (!menu
) return -1;
1516 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1520 /***********************************************************************
1523 * Find the menu item selected by a key press.
1524 * Return item id, -1 if none, -2 if we should close the menu.
1526 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1527 WCHAR Key
, BOOL ForceMenuChar
)
1532 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1534 if (!menu
|| !VerifyMenu(menu
))
1535 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1538 ITEM
*item
= menu
->rgItems
;
1540 if ( !ForceMenuChar
)
1543 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1545 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1547 LPWSTR text
= item
->Xlpstr
;
1550 const WCHAR
*p
= text
- 2;
1553 const WCHAR
*q
= p
+ 2;
1554 p
= wcschr (q
, '&');
1555 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1557 while (p
!= NULL
&& p
[1] == '&');
1558 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1563 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1564 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1566 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1567 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1568 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1569 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1574 /***********************************************************************
1575 * MenuGetBitmapItemSize
1577 * Get the size of a bitmap item.
1579 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1582 HBITMAP bmp
= lpitem
->hbmp
;
1584 size
->cx
= size
->cy
= 0;
1586 /* check if there is a magic menu item associated with this item */
1587 if (IS_MAGIC_BITMAP(bmp
))
1589 switch((INT_PTR
) bmp
)
1591 case (INT_PTR
)HBMMENU_CALLBACK
:
1593 MEASUREITEMSTRUCT measItem
;
1594 measItem
.CtlType
= ODT_MENU
;
1596 measItem
.itemID
= lpitem
->wID
;
1597 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1598 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1599 measItem
.itemData
= lpitem
->dwItemData
;
1600 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1601 size
->cx
= measItem
.itemWidth
;
1602 size
->cy
= measItem
.itemHeight
;
1603 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1608 case (INT_PTR
) HBMMENU_SYSTEM
:
1609 if (lpitem
->dwItemData
)
1611 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1615 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1616 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1617 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1618 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1619 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1620 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1621 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1622 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1623 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1624 /* FIXME: Why we need to subtract these magic values? */
1625 /* to make them smaller than the menu bar? */
1626 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1627 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1632 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1634 size
->cx
= bm
.bmWidth
;
1635 size
->cy
= bm
.bmHeight
;
1639 /***********************************************************************
1640 * MenuDrawBitmapItem
1642 * Draw a bitmap item.
1644 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1645 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1651 int w
= rect
->right
- rect
->left
;
1652 int h
= rect
->bottom
- rect
->top
;
1653 int bmp_xoffset
= 0;
1655 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1658 /* Check if there is a magic menu item associated with this item */
1659 if (IS_MAGIC_BITMAP(hbmToDraw
))
1665 switch ((INT_PTR
)hbmToDraw
)
1667 case (INT_PTR
)HBMMENU_SYSTEM
:
1668 if (lpitem
->dwItemData
)
1670 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1672 ERR("Get Item Data from this Window!!!\n");
1675 ERR("Draw Bitmap\n");
1676 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1677 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1681 PCURICON_OBJECT pIcon
= NULL
;
1682 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1684 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1685 /* only use right half of the bitmap */
1686 //bmp_xoffset = bm.bmWidth / 2;
1687 //bm.bmWidth -= bmp_xoffset;
1690 pIcon
= NC_IconForWindow(WndOwner
);
1691 // FIXME: NC_IconForWindow should reference it for us */
1692 if (pIcon
) UserReferenceObject(pIcon
);
1697 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1698 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1699 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1700 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1701 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1702 UserDereferenceObject(pIcon
);
1707 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1708 flags
= DFCS_CAPTIONRESTORE
;
1710 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1712 flags
= DFCS_CAPTIONMIN
;
1714 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1716 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1718 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1719 flags
= DFCS_CAPTIONCLOSE
;
1721 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1722 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1724 case (INT_PTR
)HBMMENU_CALLBACK
:
1726 DRAWITEMSTRUCT drawItem
;
1728 drawItem
.CtlType
= ODT_MENU
;
1730 drawItem
.itemID
= lpitem
->wID
;
1731 drawItem
.itemAction
= odaction
;
1732 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1733 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1734 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1735 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1736 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1737 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1738 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1739 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1741 drawItem
.rcItem
= *rect
;
1742 drawItem
.itemData
= lpitem
->dwItemData
;
1743 /* some applications make this assumption on the DC's origin */
1744 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1745 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1746 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1747 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1752 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1753 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1754 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1755 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1756 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1759 RECTL_vInflateRect(&r
, -1, -1);
1760 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1761 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1765 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1768 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1769 NtGdiSelectBitmap( hdcMem
, bmp
);
1770 /* handle fontsize > bitmap_height */
1771 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1773 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1774 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1775 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1776 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1777 IntGdiDeleteDC( hdcMem
, FALSE
);
1781 IntGetDialogBaseUnits(VOID
)
1790 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1792 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1793 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1794 UserReleaseDC( 0, hdc
, FALSE
);
1801 /***********************************************************************
1804 * Calculate the size of the menu item and store it in lpitem->rect.
1806 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1807 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1810 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1811 UINT arrow_bitmap_width
;
1815 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1817 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1819 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1821 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1823 if (lpitem
->fType
& MF_OWNERDRAW
)
1825 MEASUREITEMSTRUCT mis
;
1826 mis
.CtlType
= ODT_MENU
;
1828 mis
.itemID
= lpitem
->wID
;
1829 mis
.itemData
= lpitem
->dwItemData
;
1830 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1832 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1833 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1834 * width of a menufont character to the width of an owner-drawn menu.
1836 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1838 /* under at least win95 you seem to be given a standard
1839 height for the menu and the height value is ignored */
1840 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1842 Rect
.bottom
+= mis
.itemHeight
;
1844 //lpitem->cxBmp = mis.itemWidth;
1845 //lpitem->cyBmp = mis.itemHeight;
1846 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1847 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1848 lpitem
->wID
, Rect
.right
-Rect
.left
,
1849 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1851 lpitem
->xItem
= Rect
.left
;
1852 lpitem
->yItem
= Rect
.top
;
1853 lpitem
->cxItem
= Rect
.right
;
1854 lpitem
->cyItem
= Rect
.bottom
;
1859 lpitem
->xItem
= orgX
;
1860 lpitem
->yItem
= orgY
;
1861 lpitem
->cxItem
= orgX
;
1862 lpitem
->cyItem
= orgY
;
1864 if (lpitem
->fType
& MF_SEPARATOR
)
1866 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1868 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1879 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1880 /* Keep the size of the bitmap in callback mode to be able
1881 * to draw it correctly */
1882 lpitem
->cxBmp
= size
.cx
;
1883 lpitem
->cyBmp
= size
.cy
;
1884 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1885 lpitem
->cxItem
+= size
.cx
+ 2;
1886 itemheight
= size
.cy
+ 2;
1888 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1889 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1890 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1891 lpitem
->dxTab
= lpitem
->cxItem
;
1892 lpitem
->cxItem
+= arrow_bitmap_width
;
1893 } else /* hbmpItem & MenuBar */ {
1894 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1895 lpitem
->cxItem
+= size
.cx
;
1896 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1897 itemheight
= size
.cy
;
1899 /* Special case: Minimize button doesn't have a space behind it. */
1900 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1901 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1902 lpitem
->cxItem
-= 1;
1905 else if (!menuBar
) {
1906 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1907 lpitem
->cxItem
+= check_bitmap_width
;
1908 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1909 lpitem
->dxTab
= lpitem
->cxItem
;
1910 lpitem
->cxItem
+= arrow_bitmap_width
;
1913 /* it must be a text item - unless it's the system menu */
1914 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1915 HFONT hfontOld
= NULL
;
1916 RECT rc
;// = lpitem->Rect;
1917 LONG txtheight
, txtwidth
;
1919 rc
.left
= lpitem
->xItem
;
1920 rc
.top
= lpitem
->yItem
;
1921 rc
.right
= lpitem
->cxItem
; // Do this for now......
1922 rc
.bottom
= lpitem
->cyItem
;
1924 if ( lpitem
->fState
& MFS_DEFAULT
) {
1925 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1928 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1930 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1931 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1933 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1935 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1938 int n
= (int)( p
- lpitem
->Xlpstr
);
1939 /* Item contains a tab (only meaningful in popup menus) */
1940 /* get text size before the tab */
1941 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1942 DT_SINGLELINE
|DT_CALCRECT
);
1943 txtwidth
= rc
.right
- rc
.left
;
1944 p
+= 1; /* advance past the Tab */
1945 /* get text size after the tab */
1946 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1947 DT_SINGLELINE
|DT_CALCRECT
);
1948 lpitem
->dxTab
+= txtwidth
;
1949 txtheight
= max( txtheight
, tmpheight
);
1950 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1951 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1953 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1954 DT_SINGLELINE
|DT_CALCRECT
);
1955 txtwidth
= rc
.right
- rc
.left
;
1956 lpitem
->dxTab
+= txtwidth
;
1958 lpitem
->cxItem
+= 2 + txtwidth
;
1959 itemheight
= max( itemheight
,
1960 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1964 NtGdiSelectFont (hdc
, hfontOld
);
1966 } else if( menuBar
) {
1967 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1969 lpitem
->cyItem
+= itemheight
;
1970 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1973 /***********************************************************************
1974 * MENU_GetMaxPopupHeight
1977 MENU_GetMaxPopupHeight(PMENU lppop
)
1981 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1982 return lppop
->cyMax
;
1984 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
1985 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
1988 /***********************************************************************
1989 * MenuPopupMenuCalcSize
1991 * Calculate the size of a popup menu.
1993 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
1998 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1999 BOOL textandbmp
= FALSE
;
2001 Menu
->cxMenu
= Menu
->cyMenu
= 0;
2002 if (Menu
->cItems
== 0) return;
2004 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2006 NtGdiSelectFont( hdc
, ghMenuFont
);
2011 Menu
->cxTextAlign
= 0;
2013 while (start
< Menu
->cItems
)
2015 lpitem
= &Menu
->rgItems
[start
];
2017 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2018 orgX
+= MENU_COL_SPACE
;
2019 orgY
= MENU_TOP_MARGIN
;
2021 maxTab
= maxTabWidth
= 0;
2022 /* Parse items until column break or end of menu */
2023 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2026 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2028 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2029 maxX
= max(maxX
, lpitem
->cxItem
);
2030 orgY
= lpitem
->cyItem
;
2031 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2033 maxTab
= max( maxTab
, lpitem
->dxTab
);
2034 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2036 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2039 /* Finish the column (set all items to the largest width found) */
2040 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2041 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2043 lpitem
->cxItem
= maxX
;
2044 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2045 lpitem
->dxTab
= maxTab
;
2047 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2050 Menu
->cxMenu
= maxX
;
2051 /* if none of the items have both text and bitmap then
2052 * the text and bitmaps are all aligned on the left. If there is at
2053 * least one item with both text and bitmap then bitmaps are
2054 * on the left and texts left aligned with the right hand side
2056 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2058 /* space for 3d border */
2059 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2062 /* Adjust popup height if it exceeds maximum */
2063 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2064 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2065 if (Menu
->cyMenu
>= maxHeight
)
2067 Menu
->cyMenu
= maxHeight
;
2068 Menu
->dwArrowsOn
= 1;
2072 Menu
->dwArrowsOn
= 0;
2074 UserReleaseDC( 0, hdc
, FALSE
);
2077 /***********************************************************************
2078 * MENU_MenuBarCalcSize
2080 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2081 * height is off by 1 pixel which causes lengthy window relocations when
2082 * active document window is maximized/restored.
2084 * Calculate the size of the menu bar.
2086 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2089 UINT start
, i
, helpPos
;
2090 int orgX
, orgY
, maxY
;
2092 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2093 if (lppop
->cItems
== 0) return;
2094 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2095 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2097 maxY
= lprect
->top
+1;
2100 lppop
->cxTextAlign
= 0;
2101 while (start
< lppop
->cItems
)
2103 lpitem
= &lppop
->rgItems
[start
];
2104 orgX
= lprect
->left
;
2107 /* Parse items until line break or end of menu */
2108 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2110 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2112 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2114 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2115 //debug_print_menuitem (" item: ", lpitem, "");
2116 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2117 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2119 if (lpitem
->cxItem
> lprect
->right
)
2121 if (i
!= start
) break;
2122 else lpitem
->cxItem
= lprect
->right
;
2124 maxY
= max( maxY
, lpitem
->cyItem
);
2125 orgX
= lpitem
->cxItem
;
2128 /* Finish the line (set all items to the largest height found) */
2130 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2131 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2133 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2135 start
= i
; /* This works! */
2138 lprect
->bottom
= maxY
;
2139 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2141 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2142 /* the last item (if several lines, only move the last line) */
2143 if (helpPos
== ~0U) return;
2144 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2145 orgY
= lpitem
->yItem
;
2146 orgX
= lprect
->right
;
2147 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2148 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2149 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2150 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2151 lpitem
->cxItem
= orgX
;
2152 orgX
= lpitem
->xItem
;
2156 /***********************************************************************
2157 * MENU_DrawScrollArrows
2159 * Draw scroll arrows.
2161 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2163 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2167 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2168 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2172 rect
.right
= lppop
->cxMenu
;
2173 rect
.bottom
= arrow_bitmap_height
;
2174 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2175 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2177 dfcrc
.right
= arrow_bitmap_width
;
2178 dfcrc
.bottom
= arrow_bitmap_height
;
2179 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2181 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2182 rect
.bottom
= lppop
->cyMenu
;
2183 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2184 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2185 Flags
= DFCS_INACTIVE
;
2186 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2187 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2188 dfcrc
.right
= arrow_bitmap_width
;
2189 dfcrc
.bottom
= lppop
->cyMenu
;
2190 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2193 /***********************************************************************
2196 * Draw a single menu item.
2198 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2199 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2203 BOOL flat_menu
= FALSE
;
2205 UINT arrow_bitmap_width
= 0;
2209 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2212 if (lpitem
->fType
& MF_SYSMENU
)
2214 if (!(Wnd
->style
& WS_MINIMIZE
))
2216 NC_GetInsideRect(Wnd
, &rect
);
2217 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2222 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2223 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2227 if (lpitem
->fState
& MF_HILITE
)
2229 if(menuBar
&& !flat_menu
) {
2230 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2231 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2233 if (lpitem
->fState
& MF_GRAYED
)
2234 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2236 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2237 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2242 if (lpitem
->fState
& MF_GRAYED
)
2243 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2245 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2246 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2249 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2250 //rect = lpitem->Rect;
2251 rect
.left
= lpitem
->xItem
;
2252 rect
.top
= lpitem
->yItem
;
2253 rect
.right
= lpitem
->cxItem
; // Do this for now......
2254 rect
.bottom
= lpitem
->cyItem
;
2256 MENU_AdjustMenuItemRect(Menu
, &rect
);
2258 if (lpitem
->fType
& MF_OWNERDRAW
)
2261 ** Experimentation under Windows reveals that an owner-drawn
2262 ** menu is given the rectangle which includes the space it requested
2263 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2264 ** and a popup-menu arrow. This is the value of lpitem->rect.
2265 ** Windows will leave all drawing to the application except for
2266 ** the popup-menu arrow. Windows always draws that itself, after
2267 ** the menu owner has finished drawing.
2270 COLORREF old_bk
, old_text
;
2272 dis
.CtlType
= ODT_MENU
;
2274 dis
.itemID
= lpitem
->wID
;
2275 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2277 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2278 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2279 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2280 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2281 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2282 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2283 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2284 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2285 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2288 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2289 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2290 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2291 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2293 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2294 old_bk
= GreGetBkColor(hdc
);
2295 old_text
= GreGetTextColor(hdc
);
2296 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2297 IntGdiSetBkColor(hdc
, old_bk
);
2298 IntGdiSetTextColor(hdc
, old_text
);
2299 /* Draw the popup-menu arrow */
2300 if (!menuBar
&& lpitem
->spSubMenu
)
2303 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2304 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2305 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2310 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2312 if (lpitem
->fState
& MF_HILITE
)
2316 RECTL_vInflateRect (&rect
, -1, -1);
2317 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2318 RECTL_vInflateRect (&rect
, 1, 1);
2319 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2324 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2326 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2330 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2332 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2334 /* vertical separator */
2335 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2340 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2342 rc
.bottom
= Height
- 3;
2345 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2346 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2347 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2348 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2349 NtGdiSelectPen( hdc
, oldPen
);
2352 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2355 /* horizontal separator */
2356 if (lpitem
->fType
& MF_SEPARATOR
)
2363 rc
.top
= ( rc
.top
+ rc
.bottom
) / 2;
2366 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2367 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2368 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2369 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2370 NtGdiSelectPen( hdc
, oldPen
);
2373 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2377 /* helper lines for debugging */
2378 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2379 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2380 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2381 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2382 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2383 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2385 #if 0 // breaks mdi menu bar icons.
2387 /* calculate the bitmap rectangle in coordinates relative
2388 * to the item rectangle */
2390 if( lpitem
->hbmp
== HBMMENU_CALLBACK
)
2393 bmprc
.left
= lpitem
->Xlpstr
? MenuCharSize
.cx
: 0;
2395 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)
2397 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)
2400 bmprc
.left
= 4 + UserGetSystemMetrics(SM_CXMENUCHECK
);
2402 bmprc
.right
= bmprc
.left
+ lpitem
->cxBmp
;
2404 if( menuBar
&& !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2407 bmprc
.top
= (rect
.bottom
- rect
.top
- lpitem
->cyBmp
) / 2;
2409 bmprc
.bottom
= bmprc
.top
+ lpitem
->cyBmp
;
2415 INT y
= rect
.top
+ rect
.bottom
;
2417 BOOL checked
= FALSE
;
2418 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2419 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2420 /* Draw the check mark
2423 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2425 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2426 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2427 lpitem
->hbmpUnchecked
;
2428 if (bm
) /* we have a custom bitmap */
2430 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2432 NtGdiSelectBitmap( hdcMem
, bm
);
2433 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2434 check_bitmap_width
, check_bitmap_height
,
2435 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2436 IntGdiDeleteDC( hdcMem
, FALSE
);
2439 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2443 r
.right
= r
.left
+ check_bitmap_width
;
2444 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2445 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2446 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2450 if ( lpitem
->hbmp
)//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2452 RECT bmpRect
= rect
;
2453 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2454 bmpRect
.left
+= check_bitmap_width
+ 2;
2455 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2457 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2458 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2461 /* Draw the popup-menu arrow */
2462 if (lpitem
->spSubMenu
)
2465 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2466 rectTemp
.left
= rectTemp
.right
- check_bitmap_width
;
2467 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2470 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2471 rect
.left
+= check_bitmap_width
;
2472 rect
.right
-= arrow_bitmap_width
;
2474 else if( lpitem
->hbmp
)
2475 { /* Draw the bitmap */
2476 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
/*bmprc*/, Menu
, WndOwner
, odaction
, menuBar
);
2479 /* process text if present */
2485 UINT uFormat
= menuBar
?
2486 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2487 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2489 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2490 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2492 rect
.left
+= Menu
->cxTextAlign
;
2494 if ( lpitem
->fState
& MFS_DEFAULT
)
2496 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2501 rect
.left
+= lpitem
->cxBmp
;
2502 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2503 rect
.left
+= MenuCharSize
.cx
;
2504 rect
.right
-= MenuCharSize
.cx
;
2507 Text
= lpitem
->Xlpstr
;
2510 for (i
= 0; Text
[i
]; i
++)
2511 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2515 if(lpitem
->fState
& MF_GRAYED
)
2517 if (!(lpitem
->fState
& MF_HILITE
) )
2519 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2520 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2521 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2522 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2524 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2526 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2528 /* paint the shortcut text */
2529 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2531 if (L
'\t' == Text
[i
])
2533 rect
.left
= lpitem
->dxTab
;
2534 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2538 rect
.right
= lpitem
->dxTab
;
2539 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2542 if (lpitem
->fState
& MF_GRAYED
)
2544 if (!(lpitem
->fState
& MF_HILITE
) )
2546 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2547 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2548 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2549 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2551 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2553 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2558 NtGdiSelectFont (hdc
, hfontOld
);
2563 /***********************************************************************
2566 * Paint a popup menu.
2568 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2570 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2573 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2575 IntGetClientRect( wnd
, &rect
);
2577 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2578 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2579 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2583 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2585 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2588 BOOL flat_menu
= FALSE
;
2590 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2592 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2594 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2596 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2597 /* draw menu items */
2598 if (menu
&& menu
->cItems
)
2603 item
= menu
->rgItems
;
2604 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2606 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2607 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2609 /* draw scroll arrows */
2610 if (menu
->dwArrowsOn
)
2612 MENU_DrawScrollArrows(menu
, hdc
);
2618 NtGdiSelectBrush( hdc
, hPrevBrush
);
2623 /**********************************************************************
2626 PWND
MENU_IsMenuActive(VOID
)
2628 return ValidateHwndNoErr(top_popup
);
2631 /**********************************************************************
2634 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2636 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2638 void MENU_EndMenu( PWND pwnd
)
2641 menu
= UserGetMenuObject(top_popup_hmenu
);
2642 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2644 if (fInsideMenuLoop
&& top_popup
)
2646 fInsideMenuLoop
= FALSE
;
2650 ERR("Already in End loop\n");
2655 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2661 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2664 HFONT FontOld
= NULL
;
2665 BOOL flat_menu
= FALSE
;
2667 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2671 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2679 if (Rect
== NULL
|| !pMenu
)
2681 return UserGetSystemMetrics(SM_CYMENU
);
2684 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2686 FontOld
= NtGdiSelectFont(hDC
, Font
);
2688 if (pMenu
->cyMenu
== 0)
2690 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2693 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2695 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2697 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2698 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2699 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2700 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2702 if (pMenu
->cItems
== 0)
2704 NtGdiSelectFont(hDC
, FontOld
);
2705 return UserGetSystemMetrics(SM_CYMENU
);
2708 for (i
= 0; i
< pMenu
->cItems
; i
++)
2710 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2713 NtGdiSelectFont(hDC
, FontOld
);
2715 return pMenu
->cyMenu
;
2718 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2721 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2725 // No menu. Do not reserve any space
2731 return UserGetSystemMetrics(SM_CYMENU
);
2736 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2738 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2740 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2742 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2744 return lppop
->cyMenu
;
2748 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2752 /***********************************************************************
2755 * Popup menu initialization before WM_ENTERMENULOOP.
2757 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2760 PPOPUPMENU pPopupMenu
;
2762 LARGE_STRING WindowName
;
2763 UNICODE_STRING ClassName
;
2764 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2766 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2768 menu
->spwndNotify
= pWndOwner
;
2770 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2771 ex_style
= WS_EX_LAYOUTRTL
;
2773 ClassName
.Buffer
= WC_MENU
;
2774 ClassName
.Length
= 0;
2776 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2777 RtlZeroMemory(&Cs
, sizeof(Cs
));
2778 Cs
.style
= WS_POPUP
;
2779 Cs
.dwExStyle
= ex_style
;
2780 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2781 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2782 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2783 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2784 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2786 /* NOTE: In Windows, top menu popup is not owned. */
2787 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2789 if( !pWndCreated
) return FALSE
;
2792 // Setup pop up menu structure.
2794 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2796 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2798 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2799 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2800 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2802 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2803 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2804 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2805 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2806 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2808 if (pPopupMenu
->fRightButton
)
2809 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2811 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2813 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2814 menu
->fFlags
& MNF_RTOL
)
2816 pPopupMenu
->fDroppedLeft
= TRUE
;
2821 /***********************************************************************
2824 * Display a popup menu.
2826 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2827 INT x
, INT y
, INT xanchor
, INT yanchor
)
2833 USER_REFERENCE_ENTRY Ref
;
2835 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2836 pwndOwner
, menu
, id
, x
, y
, xanchor
, yanchor
);
2838 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2840 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2841 menu
->iItem
= NO_SELECTED_ITEM
;
2844 menu
->dwArrowsOn
= 0;
2845 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2847 /* adjust popup menu pos so that it fits within the desktop */
2849 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2850 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2852 /* FIXME: should use item rect */
2855 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2857 if (flags
& TPM_LAYOUTRTL
)
2858 flags
^= TPM_RIGHTALIGN
;
2860 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2861 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2863 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2864 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2866 if( x
+ width
> monitor
->rcMonitor
.right
)
2868 if( xanchor
&& x
>= width
- xanchor
)
2869 x
-= width
- xanchor
;
2871 if( x
+ width
> monitor
->rcMonitor
.right
)
2872 x
= monitor
->rcMonitor
.right
- width
;
2874 if( x
< monitor
->rcMonitor
.left
) x
= monitor
->rcMonitor
.left
;
2876 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2878 if( yanchor
&& y
>= height
+ yanchor
)
2879 y
-= height
+ yanchor
;
2881 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2882 y
= monitor
->rcMonitor
.bottom
- height
;
2884 if( y
< monitor
->rcMonitor
.top
) y
= monitor
->rcMonitor
.top
;
2886 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2890 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2895 top_popup
= menu
->hWnd
;
2896 top_popup_hmenu
= UserHMGetHandle(menu
);
2899 /* Display the window */
2900 UserRefObjectCo(pWnd
, &Ref
);
2901 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2903 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2905 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2906 UserDerefObjectCo(pWnd
);
2911 /***********************************************************************
2912 * MENU_EnsureMenuItemVisible
2914 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2916 USER_REFERENCE_ENTRY Ref
;
2917 if (lppop
->dwArrowsOn
)
2919 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2920 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2921 UINT nOldPos
= lppop
->iTop
;
2923 UINT arrow_bitmap_height
;
2924 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2926 IntGetClientRect(pWnd
, &rc
);
2928 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2930 rc
.top
+= arrow_bitmap_height
;
2931 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2933 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2934 UserRefObjectCo(pWnd
, &Ref
);
2935 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
2937 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
2938 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2939 MENU_DrawScrollArrows(lppop
, hdc
);
2940 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2942 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
2944 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
2945 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2946 MENU_DrawScrollArrows(lppop
, hdc
);
2947 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2949 UserDerefObjectCo(pWnd
);
2953 /***********************************************************************
2956 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
2957 BOOL sendMenuSelect
, PMENU topmenu
)
2962 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2964 if (!menu
|| !menu
->cItems
) return;
2966 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
2970 if (menu
->iItem
== wIndex
) return;
2972 if (menu
->fFlags
& MNF_POPUP
)
2973 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
2975 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2978 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
2979 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
2980 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
2983 NtGdiSelectFont( hdc
, ghMenuFont
);
2985 /* Clear previous highlighted item */
2986 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2988 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2989 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
2990 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
2994 /* Highlight new item (if any) */
2995 menu
->iItem
= wIndex
;
2996 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2998 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
3000 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
3001 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
3002 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
3003 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3007 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3008 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3009 ip
->fType
| ip
->fState
|
3010 (ip
->spSubMenu
? MF_POPUP
: 0) |
3011 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3013 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3016 else if (sendMenuSelect
)
3021 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3022 if (pos
!= NO_SELECTED_ITEM
)
3024 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3025 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3026 (ip
->spSubMenu
? MF_POPUP
: 0) |
3027 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3029 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3033 UserReleaseDC(pWnd
, hdc
, FALSE
);
3036 /***********************************************************************
3039 * Moves currently selected item according to the Offset parameter.
3040 * If there is no selection then it should select the last item if
3041 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3043 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3047 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3049 if ((!menu
) || (!menu
->rgItems
)) return;
3051 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3053 if ( menu
->cItems
== 1 )
3056 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3058 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3060 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3065 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3066 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3067 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3069 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3074 /***********************************************************************
3077 * Hide the sub-popup menus of this menu.
3079 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3080 BOOL SendMenuSelect
, UINT wFlags
)
3082 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3084 if ( Menu
&& top_popup
)
3088 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3090 Item
= &Menu
->rgItems
[Menu
->iItem
];
3091 if (!(Item
->spSubMenu
) ||
3092 !(Item
->fState
& MF_MOUSESELECT
)) return;
3093 Item
->fState
&= ~MF_MOUSESELECT
;
3098 if (Item
->spSubMenu
)
3101 if (!VerifyMenu(Item
->spSubMenu
)) return;
3102 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3103 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3104 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3105 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3106 co_UserDestroyWindow(pWnd
);
3108 /* Native returns handle to destroyed window */
3109 if (!(wFlags
& TPM_NONOTIFY
))
3111 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3112 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3115 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3116 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3118 Item
->spSubMenu
->hWnd
= NULL
;
3124 /***********************************************************************
3127 * Display the sub-menu of the selected item of this menu.
3128 * Return the handle of the submenu, or menu if no submenu to display.
3130 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3137 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3139 if (!Menu
) return Menu
;
3141 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3143 Item
= &Menu
->rgItems
[Menu
->iItem
];
3144 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3147 /* message must be sent before using item,
3148 because nearly everything may be changed by the application ! */
3150 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3151 if (!(Flags
& TPM_NONOTIFY
))
3153 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3154 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3155 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3158 Item
= &Menu
->rgItems
[Menu
->iItem
];
3159 //Rect = ItemInfo.Rect;
3160 Rect
.left
= Item
->xItem
;
3161 Rect
.top
= Item
->yItem
;
3162 Rect
.right
= Item
->cxItem
; // Do this for now......
3163 Rect
.bottom
= Item
->cyItem
;
3165 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3167 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3168 if (!(Item
->fState
& MF_HILITE
))
3170 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3171 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3173 NtGdiSelectFont(Dc
, ghMenuFont
);
3175 Item
->fState
|= MF_HILITE
;
3176 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3177 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3179 UserReleaseDC(pWnd
, Dc
, FALSE
);
3182 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3184 Item
->xItem
= Rect
.left
;
3185 Item
->yItem
= Rect
.top
;
3186 Item
->cxItem
= Rect
.right
; // Do this for now......
3187 Item
->cyItem
= Rect
.bottom
;
3189 Item
->fState
|= MF_MOUSESELECT
;
3191 if (IS_SYSTEM_MENU(Menu
))
3193 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3195 NC_GetSysPopupPos(pWnd
, &Rect
);
3196 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3197 Rect
.top
= Rect
.bottom
;
3198 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3199 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3203 IntGetWindowRect(pWnd
, &Rect
);
3204 if (Menu
->fFlags
& MNF_POPUP
)
3207 rc
.left
= Item
->xItem
;
3208 rc
.top
= Item
->yItem
;
3209 rc
.right
= Item
->cxItem
; // Do this for now......
3210 rc
.bottom
= Item
->cyItem
;
3212 MENU_AdjustMenuItemRect(Menu
, &rc
);
3214 /* The first item in the popup menu has to be at the
3215 same y position as the focused menu item */
3216 if(Flags
& TPM_LAYOUTRTL
)
3217 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3219 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3220 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3221 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3222 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3223 - UserGetSystemMetrics(SM_CYBORDER
);
3227 if(Flags
& TPM_LAYOUTRTL
)
3228 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3230 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3231 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3232 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3233 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3237 /* use default alignment for submenus */
3238 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3240 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3242 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3243 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3246 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3248 return Item
->spSubMenu
;
3251 /***********************************************************************
3252 * MenuExecFocusedItem
3254 * Execute a menu item (for instance when user pressed Enter).
3255 * Return the wID of the executed item. Otherwise, -1 indicating
3256 * that no menu item was executed, -2 if a popup is shown;
3257 * Have to receive the flags for the TrackPopupMenu options to avoid
3258 * sending unwanted message.
3261 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3265 TRACE("%p menu=%p\n", pmt
, Menu
);
3267 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3272 Item
= &Menu
->rgItems
[Menu
->iItem
];
3274 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3276 if (!(Item
->spSubMenu
))
3278 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3280 /* If TPM_RETURNCMD is set you return the id, but
3281 do not send a message to the owner */
3282 if (!(Flags
& TPM_RETURNCMD
))
3284 if (Menu
->fFlags
& MNF_SYSMENU
)
3286 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3287 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3291 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3293 if (dwStyle
& MNS_NOTIFYBYPOS
)
3294 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3296 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3304 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3311 /***********************************************************************
3312 * MenuSwitchTracking
3314 * Helper function for menu navigation routines.
3316 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3318 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3320 if ( pmt
->TopMenu
!= PtMenu
&&
3321 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3323 /* both are top level menus (system and menu-bar) */
3324 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3325 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3326 pmt
->TopMenu
= PtMenu
;
3330 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3333 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3336 /***********************************************************************
3339 * Return TRUE if we can go on with menu tracking.
3341 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3343 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3349 if (IS_SYSTEM_MENU(PtMenu
))
3351 item
= PtMenu
->rgItems
;
3355 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3360 if (PtMenu
->iItem
!= id
)
3361 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3363 /* If the popup menu is not already "popped" */
3364 if (!(item
->fState
& MF_MOUSESELECT
))
3366 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3371 /* Else the click was on the menu bar, finish the tracking */
3376 /***********************************************************************
3379 * Return the value of MenuExecFocusedItem if
3380 * the selected item was not a popup. Else open the popup.
3381 * A -1 return value indicates that we go on with menu tracking.
3384 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3386 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3393 if ( IS_SYSTEM_MENU(PtMenu
) )
3395 item
= PtMenu
->rgItems
;
3399 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3402 if (item
&& ( PtMenu
->iItem
== Id
))
3404 if (!(item
->spSubMenu
))
3406 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3407 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3408 return ExecutedMenuId
;
3411 /* If we are dealing with the menu bar */
3412 /* and this is a click on an already "popped" item: */
3413 /* Stop the menu tracking and close the opened submenus */
3414 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3419 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3421 PtMenu
->TimeToHide
= TRUE
;
3427 /***********************************************************************
3430 * Walks menu chain trying to find a menu pt maps to.
3432 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3437 if (!menu
) return NULL
;
3439 /* try subpopup first (if any) */
3440 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3442 pItem
= menu
->rgItems
;
3443 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3444 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3446 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3450 /* check the current window (avoiding WM_HITTEST) */
3453 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3454 INT ht
= GetNCHitEx(pWnd
, pt
);
3455 if ( menu
->fFlags
& MNF_POPUP
)
3457 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3459 else if (ht
== HTSYSMENU
)
3460 ret
= get_win_sys_menu(menu
->hWnd
);
3461 else if (ht
== HTMENU
)
3462 ret
= IntGetMenu( menu
->hWnd
);
3467 /***********************************************************************
3470 * Return TRUE if we can go on with menu tracking.
3472 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3474 UINT Index
= NO_SELECTED_ITEM
;
3478 if (IS_SYSTEM_MENU(PtMenu
))
3481 //// ReactOS only HACK: CORE-2338
3482 // Windows tracks mouse moves to the system menu but does not open it.
3483 // Only keyboard tracking can do that.
3485 TRACE("SystemMenu\n");
3486 return TRUE
; // Stay inside the Loop!
3489 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3492 if (Index
== NO_SELECTED_ITEM
)
3494 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3496 else if (PtMenu
->iItem
!= Index
)
3498 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3499 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3504 /***********************************************************************
3507 * Return the handle of the selected sub-popup menu (if any).
3509 static PMENU
MENU_GetSubPopup( PMENU menu
)
3513 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3515 item
= &menu
->rgItems
[menu
->iItem
];
3516 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3518 return item
->spSubMenu
;
3523 /***********************************************************************
3526 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3528 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3532 /* When skipping left, we need to do something special after the
3534 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3538 /* When skipping right, for the non-system menu, we need to
3539 handle the last non-special menu item (ie skip any window
3540 icons such as MDI maximize, restore or close) */
3541 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3543 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3544 while (i
< pmt
->TopMenu
->cItems
) {
3545 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3546 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3550 if (i
== pmt
->TopMenu
->cItems
) {
3554 /* When skipping right, we need to cater for the system menu */
3555 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3557 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3564 MDINEXTMENU NextMenu
;
3571 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3572 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3573 NextMenu
.hmenuNext
= NULL
;
3574 NextMenu
.hwndNext
= NULL
;
3575 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3577 TRACE("%p [%p] -> %p [%p]\n",
3578 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3580 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3582 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3583 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3585 /* switch to the menu bar */
3587 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3591 Id
= MenuTmp
->cItems
- 1;
3593 /* Skip backwards over any system predefined icons,
3594 eg. MDI close, restore etc icons */
3596 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3597 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3600 hNewMenu
= UserHMGetHandle(MenuTmp
);
3602 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3604 /* switch to the system menu */
3605 MenuTmp
= get_win_sys_menu(hNewWnd
);
3606 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3611 else /* application returned a new menu to switch to */
3613 hNewMenu
= NextMenu
.hmenuNext
;
3614 hNewWnd
= NextMenu
.hwndNext
;
3616 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3618 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3620 /* get the real system menu */
3621 MenuTmp
= get_win_sys_menu(hNewWnd
);
3622 hNewMenu
= UserHMGetHandle(MenuTmp
);
3624 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3626 /* FIXME: Not sure what to do here;
3627 * perhaps try to track NewMenu as a popup? */
3629 WARN(" -- got confused.\n");
3636 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3638 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3640 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3641 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3644 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3646 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3647 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3648 ///// Use thread pms!!!!
3649 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3650 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3651 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3652 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3655 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3656 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3663 /***********************************************************************
3666 * The idea is not to show the popup if the next input message is
3667 * going to hide it anyway.
3669 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3673 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3675 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3676 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3681 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3682 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3684 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3685 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3686 if( msg
.message
== WM_KEYDOWN
&&
3687 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3689 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3695 /* failures go through this */
3696 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3700 /***********************************************************************
3703 * Handle a VK_ESCAPE key event in a menu.
3705 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3707 BOOL EndMenu
= TRUE
;
3709 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3711 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3713 PMENU MenuPrev
, MenuTmp
;
3715 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3717 /* close topmost popup */
3718 while (MenuTmp
!= pmt
->CurrentMenu
)
3721 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3724 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3725 pmt
->CurrentMenu
= MenuPrev
;
3733 /***********************************************************************
3736 * Handle a VK_LEFT key event in a menu.
3738 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
, UINT msg
)
3740 PMENU MenuTmp
, MenuPrev
;
3743 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3745 /* Try to move 1 column left (if possible) */
3746 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3748 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3752 /* close topmost popup */
3753 while (MenuTmp
!= pmt
->CurrentMenu
)
3756 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3759 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3760 pmt
->CurrentMenu
= MenuPrev
;
3762 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3764 /* move menu bar selection if no more popups are left */
3766 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3767 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3769 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3771 /* A sublevel menu was displayed - display the next one
3772 * unless there is another displacement coming up */
3774 if (!MENU_SuspendPopup(pmt
, msg
))
3775 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3781 /***********************************************************************
3784 * Handle a VK_RIGHT key event in a menu.
3786 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
, UINT msg
)
3791 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3792 pmt
->CurrentMenu
, pmt
->TopMenu
);
3794 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3796 /* If already displaying a popup, try to display sub-popup */
3798 menutmp
= pmt
->CurrentMenu
;
3799 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3801 /* if subpopup was displayed then we are done */
3802 if (menutmp
!= pmt
->CurrentMenu
) return;
3805 /* Check to see if there's another column */
3806 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3808 TRACE("Going to %d.\n", NextCol
);
3809 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3813 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3815 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3817 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3818 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3825 /* try to move to the next item */
3826 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3827 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3829 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3831 if ( !MENU_SuspendPopup(pmt
, msg
) )
3832 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3837 /***********************************************************************
3840 * Menu tracking code.
3842 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3843 PWND pwnd
, const RECT
*lprect
)
3847 INT executedMenuId
= -1;
3851 BOOL enterIdleSent
= FALSE
;
3852 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3854 if (pti
!= pwnd
->head
.pti
)
3856 ERR("Not the same PTI!!!!\n");
3860 mt
.CurrentMenu
= pmenu
;
3866 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3867 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3868 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3870 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3872 if (wFlags
& TPM_BUTTONDOWN
)
3874 /* Get the result in order to start the tracking or not */
3875 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3876 fInsideMenuLoop
= fRemove
;
3879 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3881 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3883 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3884 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3885 co_UserSetCapture(NULL
); /* release the capture */
3889 capture_win
= IntGetCapture();
3891 while (fInsideMenuLoop
)
3893 BOOL ErrorExit
= FALSE
;
3894 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3897 /* we have to keep the message in the queue until it's
3898 * clear that menu loop is not over yet. */
3902 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3904 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3905 /* remove the message from the queue */
3906 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3910 /* ReactOS Checks */
3911 if (!VerifyWnd(mt
.OwnerWnd
) ||
3912 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3913 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3914 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3916 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3922 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3923 enterIdleSent
= TRUE
;
3924 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3926 co_IntWaitMessage(NULL
, 0, 0);
3930 if (ErrorExit
) break; // Gracefully dropout.
3932 /* check if EndMenu() tried to cancel us, by posting this message */
3933 if (msg
.message
== WM_CANCELMODE
)
3935 /* we are now out of the loop */
3936 fInsideMenuLoop
= FALSE
;
3938 /* remove the message from the queue */
3939 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3941 /* break out of internal loop, ala ESCAPE */
3947 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3948 enterIdleSent
=FALSE
;
3951 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3954 * Use the mouse coordinates in lParam instead of those in the MSG
3955 * struct to properly handle synthetic messages. They are already
3956 * in screen coordinates.
3958 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3959 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3961 /* Find a menu for this mouse event */
3962 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3966 /* no WM_NC... messages in captured state */
3968 case WM_RBUTTONDBLCLK
:
3969 case WM_RBUTTONDOWN
:
3970 if (!(wFlags
& TPM_RIGHTBUTTON
))
3972 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3976 case WM_LBUTTONDBLCLK
:
3977 case WM_LBUTTONDOWN
:
3978 /* If the message belongs to the menu, removes it from the queue */
3979 /* Else, end menu tracking */
3980 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3981 fInsideMenuLoop
= fRemove
;
3982 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3983 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3987 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3990 /* Check if a menu was selected by the mouse */
3993 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
3995 /* End the loop if executedMenuId is an item ID */
3996 /* or if the job was done (executedMenuId = 0). */
3997 fRemove
= (executedMenuId
!= -1);
3998 fInsideMenuLoop
= !fRemove
;
4000 /* No menu was selected by the mouse */
4001 /* if the function was called by TrackPopupMenu, continue
4002 with the menu tracking. If not, stop it */
4004 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4009 /* the selected menu item must be changed every time */
4010 /* the mouse moves. */
4013 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4015 } /* switch(msg.message) - mouse */
4017 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4019 fRemove
= TRUE
; /* Keyboard messages are always removed */
4028 fInsideMenuLoop
= FALSE
;
4033 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4034 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4038 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4039 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4040 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4041 else /* otherwise try to move selection */
4042 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4046 MENU_KeyLeft( &mt
, wFlags
, msg
.message
);
4050 MENU_KeyRight( &mt
, wFlags
, msg
.message
);
4054 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4060 hi
.cbSize
= sizeof(HELPINFO
);
4061 hi
.iContextType
= HELPINFO_MENUITEM
;
4062 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4065 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4066 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4067 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4068 hi
.MousePos
= msg
.pt
;
4069 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4074 IntTranslateKbdMessage(&msg
, 0);
4077 break; /* WM_KEYDOWN */
4085 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4087 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4088 fEndMenu
= (executedMenuId
!= -2);
4089 fInsideMenuLoop
= !fEndMenu
;
4093 /* Hack to avoid control chars. */
4094 /* We will find a better way real soon... */
4095 if (msg
.wParam
< 32) break;
4097 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4099 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4100 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4103 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4104 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4105 fEndMenu
= (executedMenuId
!= -2);
4106 fInsideMenuLoop
= !fEndMenu
;
4110 } /* switch(msg.message) - kbd */
4114 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4115 IntDispatchMessage( &msg
);
4119 if (fInsideMenuLoop
) fRemove
= TRUE
;
4121 /* finally remove message from the queue */
4123 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4124 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4125 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4128 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4129 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4130 co_UserSetCapture(NULL
); /* release the capture */
4132 /* If dropdown is still painted and the close box is clicked on
4133 then the menu will be destroyed as part of the DispatchMessage above.
4134 This will then invalidate the menu handle in mt.hTopMenu. We should
4135 check for this first. */
4136 if ( VerifyMenu( mt
.TopMenu
) )
4138 if (VerifyWnd(mt
.OwnerWnd
))
4140 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4142 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4144 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4147 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4149 co_UserDestroyWindow(pwndTM
);
4151 mt
.TopMenu
->hWnd
= NULL
;
4153 if (!(wFlags
& TPM_NONOTIFY
))
4155 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4156 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4159 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4160 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4163 /* Reset the variable for hiding menu */
4164 mt
.TopMenu
->TimeToHide
= FALSE
;
4167 EngSetLastError( ERROR_SUCCESS
);
4168 /* The return value is only used by TrackPopupMenu */
4169 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4170 if (executedMenuId
== -1) executedMenuId
= 0;
4171 return executedMenuId
;
4174 /***********************************************************************
4177 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4180 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4182 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4184 co_UserHideCaret(0);
4186 /* This makes the menus of applications built with Delphi work.
4187 * It also enables menus to be displayed in more than one window,
4188 * but there are some bugs left that need to be fixed in this case.
4192 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4196 top_popup
= Menu
->hWnd
;
4197 top_popup_hmenu
= UserHMGetHandle(Menu
);
4200 fInsideMenuLoop
= TRUE
;
4203 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4204 if (!(wFlags
& TPM_NONOTIFY
))
4206 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4210 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4212 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4213 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4214 co_UserSetCapture(capture_win
); // 2
4215 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4217 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4219 if (!(wFlags
& TPM_NONOTIFY
))
4221 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4222 /* If an app changed/recreated menu bar entries in WM_INITMENU
4223 * menu sizes will be recalculated once the menu created/shown.
4227 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4229 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4234 /***********************************************************************
4237 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4239 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4241 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4243 if (!(wFlags
& TPM_NONOTIFY
))
4244 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4246 co_UserShowCaret(0);
4249 top_popup_hmenu
= NULL
;
4254 /***********************************************************************
4255 * MenuTrackMouseMenuBar
4257 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4259 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4261 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) ); // See 74276 and CORE-12801
4262 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4264 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4266 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4267 if (VerifyMenu(pMenu
))
4269 /* map point to parent client coordinates */
4270 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4271 if (Parent
!= UserGetDesktopWindow())
4273 IntScreenToClient(Parent
, &pt
);
4276 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4277 /* fetch the window menu again, it may have changed */
4278 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4279 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4280 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4284 /***********************************************************************
4285 * MenuTrackKbdMenuBar
4287 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4289 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4291 UINT uItem
= NO_SELECTED_ITEM
;
4293 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4295 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4297 /* find window that has a menu */
4299 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4300 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4302 /* check if we have to track a system menu */
4304 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4305 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4307 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4308 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4310 wParam
|= HTSYSMENU
; /* prevent item lookup */
4313 if (!VerifyMenu( TrackMenu
)) return;
4315 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4317 /* fetch the window menu again, it may have changed */
4318 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4320 if( wChar
&& wChar
!= ' ' )
4322 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4323 if ( uItem
>= (UINT
)(-2) )
4325 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4326 /* schedule end of menu tracking */
4327 wFlags
|= TF_ENDMENU
;
4332 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4334 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4336 if( uItem
== NO_SELECTED_ITEM
)
4337 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4339 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4343 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4344 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4347 /**********************************************************************
4348 * TrackPopupMenuEx (USER32.@)
4350 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4351 PWND pWnd
, LPTPMPARAMS lpTpm
)
4354 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4356 if (pti
!= pWnd
->head
.pti
)
4358 ERR("Must be the same pti!\n");
4362 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4363 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4364 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4366 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4368 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4372 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4374 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4376 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4377 if (!(wFlags
& TPM_NONOTIFY
))
4379 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4382 if (menu
->fFlags
& MNF_SYSMENU
)
4383 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4385 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4386 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4387 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4390 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4391 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4392 co_UserSetCapture(NULL
); /* release the capture */
4395 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4399 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4400 if (pwndM
) // wine hack around this with their destroy function.
4402 if (!(pWnd
->state
& WNDS_DESTROYED
))
4403 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4407 if (!(wFlags
& TPM_NONOTIFY
))
4409 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4410 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4428 PPOPUPMENU pPopupMenu
;
4432 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4438 if (Message
!= WM_NCCREATE
)
4440 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4443 Wnd
->fnid
= FNID_MENU
;
4444 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4445 if (pPopupMenu
== NULL
)
4449 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4450 pPopupMenu
->spwndPopupMenu
= Wnd
;
4451 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4452 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4458 if (Wnd
->fnid
!= FNID_MENU
)
4460 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4463 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4471 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4472 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4476 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4477 *lResult
= MA_NOACTIVATE
;
4483 IntBeginPaint(Wnd
, &ps
);
4484 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4485 IntEndPaint(Wnd
, &ps
);
4489 case WM_PRINTCLIENT
:
4491 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4500 /* zero out global pointer in case resident popup window was destroyed. */
4503 if (UserHMGetHandle(Wnd
) == top_popup
)
4506 top_popup_hmenu
= NULL
;
4511 ERR("No Window Pop Up!\n");
4517 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4518 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4519 Wnd
->fnid
= FNID_DESTROY
;
4523 case MM_SETMENUHANDLE
: // wine'isms
4526 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4529 ERR("Bad Menu Handle\n");
4532 pPopupMenu
->spmenu
= pmenu
;
4536 case MM_GETMENUHANDLE
: // wine'isms
4538 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4542 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4544 ERR("Someone is passing unknown menu messages %d\n",Message
);
4546 TRACE("PMWP to IDWP %d\n",Message
);
4547 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4555 IntHiliteMenuItem(PWND WindowObject
,
4561 UINT uItem
= uItemHilite
;
4563 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4565 if (uHilite
& MF_HILITE
)
4567 MenuItem
->fState
|= MF_HILITE
;
4571 MenuItem
->fState
&= ~MF_HILITE
;
4573 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4574 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4575 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4577 return TRUE
; // Always returns true!!!!
4581 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4585 DWORD dwExStyle
= 0;
4586 BOOLEAN retValue
= TRUE
;
4588 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4590 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4592 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4594 dwStyle
= pWindowObject
->style
;
4595 dwExStyle
= pWindowObject
->ExStyle
;
4597 bti
->rcTitleBar
.top
= 0;
4598 bti
->rcTitleBar
.left
= 0;
4599 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4600 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4602 /* Is it iconiced ? */
4603 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4605 /* Remove frame from rectangle */
4606 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4608 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4609 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4611 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4613 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4614 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4616 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4618 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4619 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4622 /* We have additional border information if the window
4623 * is a child (but not an MDI child) */
4624 if ( (dwStyle
& WS_CHILD
) &&
4625 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4627 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4629 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4630 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4633 if (dwExStyle
& WS_EX_STATICEDGE
)
4635 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4636 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4641 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4642 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4643 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4645 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4646 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4648 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4649 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4653 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4654 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4655 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4658 if (dwStyle
& WS_CAPTION
)
4660 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4661 if (dwStyle
& WS_SYSMENU
)
4663 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4665 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4666 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4670 if (!(dwStyle
& WS_MINIMIZEBOX
))
4672 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4674 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4676 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4680 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4682 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4684 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4686 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4691 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4692 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4693 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4694 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4699 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4704 EngSetLastError(ERROR_INVALID_PARAMETER
);
4716 LPCMENUITEMINFOW UnsafeItemInfo
,
4717 PUNICODE_STRING lpstr
)
4720 ROSMENUITEMINFO ItemInfo
;
4722 /* Try to copy the whole MENUITEMINFOW structure */
4723 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4724 if (NT_SUCCESS(Status
))
4726 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4727 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4729 EngSetLastError(ERROR_INVALID_PARAMETER
);
4732 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4735 /* Try to copy without last field (not present in older versions) */
4736 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4737 if (NT_SUCCESS(Status
))
4739 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4741 EngSetLastError(ERROR_INVALID_PARAMETER
);
4744 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4745 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4748 SetLastNtError(Status
);
4752 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4757 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4762 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4764 if (pItem
->spSubMenu
)
4766 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4769 return (pItem
->fType
| pItem
->fState
);
4772 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4777 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4782 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4784 if (pItem
->spSubMenu
)
4786 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4792 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4794 PMENU menu
, pSubTarget
;
4796 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4797 return NO_SELECTED_ITEM
;
4799 pSubTarget
= UserGetMenuObject(hSubTarget
);
4801 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4803 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4809 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4811 PWINSTATION_OBJECT WinStaObject
;
4815 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4817 if (gpepCSRSS
!= CurrentProcess
)
4820 * gpepCSRSS does not have a Win32WindowStation
4823 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4829 if (!NT_SUCCESS(Status
))
4831 ERR("Validation of window station handle (%p) failed\n",
4832 CurrentProcess
->Win32WindowStation
);
4833 SetLastNtError(Status
);
4836 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4837 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4839 ERR("Desktop Window Station does not match Process one!\n");
4841 ObDereferenceObject(WinStaObject
);
4845 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4848 if (Menu
) UserDereferenceObject(Menu
);
4849 return (HMENU
)Handle
;
4857 PROSMENUITEMINFO ItemInfo
,
4859 PUNICODE_STRING lpstr
)
4864 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4866 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4871 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4875 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4885 PROSMENUITEMINFO UnsafeItemInfo
,
4887 PUNICODE_STRING lpstr
)
4890 ROSMENUITEMINFO ItemInfo
;
4895 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4896 if (! NT_SUCCESS(Status
))
4898 SetLastNtError(Status
);
4901 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4902 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4903 Size
!= sizeof(ROSMENUITEMINFO
) )
4905 EngSetLastError(ERROR_INVALID_PARAMETER
);
4908 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4909 if (! NT_SUCCESS(Status
))
4911 SetLastNtError(Status
);
4914 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4916 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4917 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4919 EngSetLastError(ERROR_INVALID_PARAMETER
);
4923 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4925 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4926 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4929 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4935 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4939 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4942 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4943 if (! NT_SUCCESS(Status
))
4945 SetLastNtError(Status
);
4957 PROSMENUINFO UnsafeMenuInfo
,
4963 ROSMENUINFO MenuInfo
;
4965 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4966 if (! NT_SUCCESS(Status
))
4968 SetLastNtError(Status
);
4971 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4973 EngSetLastError(ERROR_INVALID_PARAMETER
);
4976 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4977 if (! NT_SUCCESS(Status
))
4979 SetLastNtError(Status
);
4986 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4991 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4994 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
4995 if (! NT_SUCCESS(Status
))
4997 SetLastNtError(Status
);
5017 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5019 Rect
->left
= MenuItem
->xItem
;
5020 Rect
->top
= MenuItem
->yItem
;
5021 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5022 Rect
->bottom
= MenuItem
->cyItem
;
5026 ERR("Failed Item Lookup! %u\n", uItem
);
5032 HWND hWnd
= Menu
->hWnd
;
5033 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5036 if (Menu
->fFlags
& MNF_POPUP
)
5038 XMove
= pWnd
->rcClient
.left
;
5039 YMove
= pWnd
->rcClient
.top
;
5043 XMove
= pWnd
->rcWindow
.left
;
5044 YMove
= pWnd
->rcWindow
.top
;
5047 Rect
->left
+= XMove
;
5049 Rect
->right
+= XMove
;
5050 Rect
->bottom
+= YMove
;
5055 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5057 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5058 HMENU hSysMenu
, hNewMenu
= NULL
;
5059 ROSMENUITEMINFO ItemInfoSet
= {0};
5060 ROSMENUITEMINFO ItemInfo
= {0};
5061 UNICODE_STRING MenuName
;
5063 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5064 if (NULL
== hSysMenu
)
5068 SysMenu
= UserGetMenuObject(hSysMenu
);
5069 if (NULL
== SysMenu
)
5071 UserDestroyMenu(hSysMenu
);
5075 SysMenu
->fFlags
|= MNF_SYSMENU
;
5076 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5080 //hNewMenu = co_IntLoadSysMenuTemplate();
5081 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5083 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5084 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5088 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5089 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5090 //ERR("%wZ\n",&MenuName);
5095 IntReleaseMenuObject(SysMenu
);
5096 UserDestroyMenu(hSysMenu
);
5099 Menu
= UserGetMenuObject(hNewMenu
);
5102 IntReleaseMenuObject(SysMenu
);
5103 UserDestroyMenu(hSysMenu
);
5107 // Do the rest in here.
5109 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5111 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5112 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5113 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5114 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5115 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5116 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5117 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5118 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5119 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5120 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5122 NewMenu
= IntCloneMenu(Menu
);
5123 if (NewMenu
== NULL
)
5125 IntDestroyMenuObject(Menu
, FALSE
);
5126 IntDestroyMenuObject(SysMenu
, FALSE
);
5130 IntReleaseMenuObject(NewMenu
);
5131 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5133 IntDestroyMenuObject(Menu
, FALSE
);
5141 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5143 if (Window
->pcls
->style
& CS_NOCLOSE
)
5144 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5146 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5147 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5148 ItemInfo
.fType
= MF_POPUP
;
5149 ItemInfo
.fState
= MFS_ENABLED
;
5150 ItemInfo
.dwTypeData
= NULL
;
5152 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5153 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5157 ERR("failed to load system menu!\n");
5162 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5168 if (Window
->SystemMenu
)
5170 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5171 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5173 IntDestroyMenuObject(Menu
, TRUE
);
5174 Window
->SystemMenu
= NULL
;
5180 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5181 if ((!Window
->SystemMenu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5183 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5184 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5188 if (Window
->SystemMenu
)
5190 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5191 /* Store the dummy sysmenu handle to facilitate the refresh */
5192 /* of the close button if the SC_CLOSE item change */
5193 Menu
= UserGetMenuObject(hMenu
);
5196 Menu
->spwndNotify
= Window
;
5197 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5205 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5209 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5211 if (Window
->SystemMenu
)
5213 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5216 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5217 IntDestroyMenuObject(OldMenu
, TRUE
);
5221 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5223 { // Use spmenuSys too!
5224 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5227 Window
->SystemMenu
= NULL
;
5229 if (Menu
&& Window
!= Menu
->spwndNotify
)
5231 Menu
->spwndNotify
= Window
;
5243 PMENU OldMenu
, NewMenu
= NULL
;
5245 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5247 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5248 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5252 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5260 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5261 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5270 NewMenu
= IntGetMenuObject(Menu
);
5271 if (NULL
== NewMenu
)
5273 if (NULL
!= OldMenu
)
5275 IntReleaseMenuObject(OldMenu
);
5277 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5280 if (NULL
!= NewMenu
->hWnd
)
5282 /* Can't use the same menu for two windows */
5283 if (NULL
!= OldMenu
)
5285 IntReleaseMenuObject(OldMenu
);
5287 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5293 Wnd
->IDMenu
= (UINT
) Menu
;
5294 if (NULL
!= NewMenu
)
5296 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5297 IntReleaseMenuObject(NewMenu
);
5299 if (NULL
!= OldMenu
)
5301 OldMenu
->hWnd
= NULL
;
5302 IntReleaseMenuObject(OldMenu
);
5309 /* FUNCTIONS *****************************************************************/
5314 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5329 UserEnterExclusive();
5331 if(!(Window
= UserGetWindowObject(hwnd
)))
5333 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5338 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5345 Rect
.left
= leftBorder
;
5346 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5350 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5352 UserReleaseDC( 0, hdc
, FALSE
);
5363 NtUserCheckMenuItem(
5369 DECLARE_RETURN(DWORD
);
5371 TRACE("Enter NtUserCheckMenuItem\n");
5372 UserEnterExclusive();
5374 if(!(Menu
= UserGetMenuObject(hMenu
)))
5379 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5382 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5397 DECLARE_RETURN(BOOL
);
5399 TRACE("Enter NtUserDeleteMenu\n");
5400 UserEnterExclusive();
5402 if(!(Menu
= UserGetMenuObject(hMenu
)))
5407 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5410 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5416 * NtUserGetSystemMenu
5418 * The NtUserGetSystemMenu function allows the application to access the
5419 * window menu (also known as the system menu or the control menu) for
5420 * copying and modifying.
5424 * Handle to the window that will own a copy of the window menu.
5426 * Specifies the action to be taken. If this parameter is FALSE,
5427 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5428 * currently in use. The copy is initially identical to the window menu
5429 * but it can be modified.
5430 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5431 * to the default state. The previous window menu, if any, is destroyed.
5434 * If the bRevert parameter is FALSE, the return value is a handle to a
5435 * copy of the window menu. If the bRevert parameter is TRUE, the return
5443 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5447 DECLARE_RETURN(HMENU
);
5449 TRACE("Enter NtUserGetSystemMenu\n");
5452 if (!(Window
= UserGetWindowObject(hWnd
)))
5457 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5462 RETURN(Menu
->head
.h
);
5465 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5471 * NtUserSetSystemMenu
5478 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5480 BOOL Result
= FALSE
;
5483 DECLARE_RETURN(BOOL
);
5485 TRACE("Enter NtUserSetSystemMenu\n");
5486 UserEnterExclusive();
5488 if (!(Window
= UserGetWindowObject(hWnd
)))
5496 * Assign new menu handle and Up the Lock Count.
5498 if (!(Menu
= IntGetMenuObject(hMenu
)))
5503 Result
= IntSetSystemMenu(Window
, Menu
);
5506 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5511 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5520 NtUserGetTitleBarInfo(
5525 TITLEBARINFO bartitleinfo
;
5526 DECLARE_RETURN(BOOLEAN
);
5527 BOOLEAN retValue
= TRUE
;
5529 TRACE("Enter NtUserGetTitleBarInfo\n");
5530 UserEnterExclusive();
5532 /* Vaildate the windows handle */
5533 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5535 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5541 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5542 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5543 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5545 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5547 /* Fail copy the data */
5548 EngSetLastError(ERROR_INVALID_PARAMETER
);
5553 /* Get the tile bar info */
5556 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5561 /* Copy our buffer to user mode buffer bti */
5562 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5563 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5565 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5567 /* Fail copy the data */
5568 EngSetLastError(ERROR_INVALID_PARAMETER
);
5578 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5586 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5589 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5591 if(!(Menu
= UserGetMenuObject(hMenu
)))
5596 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5598 EngSetLastError(ERROR_ACCESS_DENIED
);
5601 return IntDestroyMenuObject(Menu
, FALSE
);
5612 DECLARE_RETURN(BOOL
);
5614 TRACE("Enter NtUserDestroyMenu\n");
5615 UserEnterExclusive();
5617 if(!(Menu
= UserGetMenuObject(hMenu
)))
5621 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5623 EngSetLastError(ERROR_ACCESS_DENIED
);
5626 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5629 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5638 NtUserEnableMenuItem(
5644 DECLARE_RETURN(UINT
);
5646 TRACE("Enter NtUserEnableMenuItem\n");
5647 UserEnterExclusive();
5649 if(!(Menu
= UserGetMenuObject(hMenu
)))
5654 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5657 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5669 TRACE("Enter NtUserEndMenu\n");
5670 UserEnterExclusive();
5671 /* if ( gptiCurrent->pMenuState &&
5672 gptiCurrent->pMenuState->pGlobalPopupMenu )
5674 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5677 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5680 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5682 if (fInsideMenuLoop
&& top_popup
)
5684 fInsideMenuLoop
= FALSE
;
5685 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5688 TRACE("Leave NtUserEndMenu\n");
5696 NtUserGetMenuBarInfo(
5706 PPOPUPMENU pPopupMenu
;
5707 USER_REFERENCE_ENTRY Ref
;
5708 NTSTATUS Status
= STATUS_SUCCESS
;
5710 DECLARE_RETURN(BOOL
);
5712 TRACE("Enter NtUserGetMenuBarInfo\n");
5715 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5717 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5721 UserRefObjectCo(pWnd
, &Ref
);
5723 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5725 kmbi
.hwndMenu
= NULL
;
5726 kmbi
.fBarFocused
= FALSE
;
5727 kmbi
.fFocused
= FALSE
;
5732 if (!pWnd
->pcls
->fnid
)
5734 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5736 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5737 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5740 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5741 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5742 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5743 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5745 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5747 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5752 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5753 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5754 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5757 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5758 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5759 hMenu
= UserHMGetHandle(Menu
);
5770 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5771 kmbi
.cbSize
= pmbi
->cbSize
;
5773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5779 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5781 EngSetLastError(ERROR_INVALID_PARAMETER
);
5785 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5789 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5794 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5795 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5796 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5797 TRACE("idItem a 0 %d\n",Ret
);
5801 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5802 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5806 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5807 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5810 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5811 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5813 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5818 kmbi
.fFocused
= kmbi
.fBarFocused
;
5823 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5824 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5826 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5828 Status
= _SEH2_GetExceptionCode();
5832 if (!NT_SUCCESS(Status
))
5834 SetLastNtError(Status
);
5841 if (pWnd
) UserDerefObjectCo(pWnd
);
5842 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5855 PMENU Menu
, SubMenu
;
5858 DECLARE_RETURN(UINT
);
5860 TRACE("Enter NtUserGetMenuIndex\n");
5863 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5864 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5867 MenuItem
= Menu
->rgItems
;
5868 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5870 if (MenuItem
->spSubMenu
== SubMenu
)
5871 RETURN(MenuItem
->wID
);
5876 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5885 NtUserGetMenuItemRect(
5896 NTSTATUS Status
= STATUS_SUCCESS
;
5897 DECLARE_RETURN(BOOL
);
5899 TRACE("Enter NtUserGetMenuItemRect\n");
5902 if (!(Menu
= UserGetMenuObject(hMenu
)))
5907 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5909 Rect
.left
= MenuItem
->xItem
;
5910 Rect
.top
= MenuItem
->yItem
;
5911 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5912 Rect
.bottom
= MenuItem
->cyItem
;
5922 if (lprcItem
== NULL
) RETURN( FALSE
);
5924 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5926 if (Menu
->fFlags
& MNF_POPUP
)
5928 XMove
= ReferenceWnd
->rcClient
.left
;
5929 YMove
= ReferenceWnd
->rcClient
.top
;
5933 XMove
= ReferenceWnd
->rcWindow
.left
;
5934 YMove
= ReferenceWnd
->rcWindow
.top
;
5939 Rect
.right
+= XMove
;
5940 Rect
.bottom
+= YMove
;
5944 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5946 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5948 Status
= _SEH2_GetExceptionCode();
5952 if (!NT_SUCCESS(Status
))
5954 SetLastNtError(Status
);
5960 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5969 NtUserHiliteMenuItem(
5977 DECLARE_RETURN(BOOLEAN
);
5979 TRACE("Enter NtUserHiliteMenuItem\n");
5980 UserEnterExclusive();
5982 if(!(Window
= UserGetWindowObject(hWnd
)))
5984 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5988 if(!(Menu
= UserGetMenuObject(hMenu
)))
5990 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5994 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
5997 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
6007 NtUserDrawMenuBarTemp(
6017 NTSTATUS Status
= STATUS_SUCCESS
;
6018 DECLARE_RETURN(DWORD
);
6020 ERR("Enter NtUserDrawMenuBarTemp\n");
6021 UserEnterExclusive();
6023 if(!(Window
= UserGetWindowObject(hWnd
)))
6025 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6029 if(!(Menu
= UserGetMenuObject(hMenu
)))
6031 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6037 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6038 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6040 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6042 Status
= _SEH2_GetExceptionCode();
6046 if (Status
!= STATUS_SUCCESS
)
6048 SetLastNtError(Status
);
6052 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6055 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6064 NtUserMenuItemFromPoint(
6074 DECLARE_RETURN(int);
6076 TRACE("Enter NtUserMenuItemFromPoint\n");
6077 UserEnterExclusive();
6079 if (!(Menu
= UserGetMenuObject(hMenu
)))
6084 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6089 X
-= Window
->rcWindow
.left
;
6090 Y
-= Window
->rcWindow
.top
;
6093 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6097 Rect
.left
= mi
->xItem
;
6098 Rect
.top
= mi
->yItem
;
6099 Rect
.right
= mi
->cxItem
;
6100 Rect
.bottom
= mi
->cyItem
;
6102 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6104 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6110 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6113 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6133 UserEnterExclusive();
6135 if(!(Window
= UserGetWindowObject(hWnd
)))
6137 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6142 Rect
.left
= leftBorder
;
6143 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6147 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6164 DECLARE_RETURN(BOOL
);
6166 TRACE("Enter NtUserRemoveMenu\n");
6167 UserEnterExclusive();
6169 if(!(Menu
= UserGetMenuObject(hMenu
)))
6174 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6177 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6194 DECLARE_RETURN(BOOL
);
6196 TRACE("Enter NtUserSetMenu\n");
6197 UserEnterExclusive();
6199 if (!(Window
= UserGetWindowObject(hWnd
)))
6204 if (!IntSetMenu(Window
, Menu
, &Changed
))
6209 // Not minimized and please repaint!!!
6210 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6212 USER_REFERENCE_ENTRY Ref
;
6213 UserRefObjectCo(Window
, &Ref
);
6214 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6215 UserDerefObjectCo(Window
);
6221 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6230 NtUserSetMenuContextHelpId(
6232 DWORD dwContextHelpId
)
6235 DECLARE_RETURN(BOOL
);
6237 TRACE("Enter NtUserSetMenuContextHelpId\n");
6238 UserEnterExclusive();
6240 if(!(Menu
= UserGetMenuObject(hMenu
)))
6245 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6248 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6257 NtUserSetMenuDefaultItem(
6263 DECLARE_RETURN(BOOL
);
6265 TRACE("Enter NtUserSetMenuDefaultItem\n");
6266 UserEnterExclusive();
6268 if(!(Menu
= UserGetMenuObject(hMenu
)))
6273 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6276 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6285 NtUserSetMenuFlagRtoL(
6289 DECLARE_RETURN(BOOL
);
6291 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6292 UserEnterExclusive();
6294 if(!(Menu
= UserGetMenuObject(hMenu
)))
6299 RETURN(IntSetMenuFlagRtoL(Menu
));
6302 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6311 NtUserThunkedMenuInfo(
6316 DECLARE_RETURN(BOOL
);
6318 TRACE("Enter NtUserThunkedMenuInfo\n");
6319 UserEnterExclusive();
6321 if (!(Menu
= UserGetMenuObject(hMenu
)))
6326 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6329 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6338 NtUserThunkedMenuItemInfo(
6343 LPMENUITEMINFOW lpmii
,
6344 PUNICODE_STRING lpszCaption
)
6348 UNICODE_STRING lstrCaption
;
6349 DECLARE_RETURN(BOOL
);
6351 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6352 UserEnterExclusive();
6354 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6355 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6357 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6359 if (!(Menu
= UserGetMenuObject(hMenu
)))
6364 /* Check if we got a Caption */
6365 if (lpszCaption
&& lpszCaption
->Buffer
)
6367 /* Copy the string to kernel mode */
6368 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6371 if (!NT_SUCCESS(Status
))
6373 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6374 SetLastNtError(Status
);
6379 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6381 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6384 if (lstrCaption
.Buffer
)
6386 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6389 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6398 NtUserTrackPopupMenuEx(
6410 USER_REFERENCE_ENTRY Ref
;
6412 TRACE("Enter NtUserTrackPopupMenuEx\n");
6413 UserEnterExclusive();
6414 /* Parameter check */
6415 if (!(menu
= UserGetMenuObject( hMenu
)))
6417 ERR("TPME : Invalid Menu handle.\n");
6418 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6422 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6424 ERR("TPME : Invalid Window handle.\n");
6432 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6437 _SEH2_YIELD(goto Exit
);
6441 UserRefObjectCo(pWnd
, &Ref
);
6442 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6443 UserDerefObjectCo(pWnd
);
6446 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);