2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: win32ss/user/ntuser/menu.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
10 DBG_DEFAULT_CHANNEL(UserMenu
);
12 /* INTERNAL ******************************************************************/
14 HFONT ghMenuFont
= NULL
;
15 HFONT ghMenuFontBold
= NULL
;
16 static SIZE MenuCharSize
;
18 /* Use global popup window because there's no way 2 menus can
19 * be tracked at the same time. */
20 static HWND top_popup
= NULL
;
21 static HMENU top_popup_hmenu
= NULL
;
23 BOOL fInsideMenuLoop
= FALSE
;
24 BOOL fInEndMenu
= FALSE
;
26 /* internal popup menu window messages */
28 #define MM_SETMENUHANDLE (WM_USER + 0)
29 #define MM_GETMENUHANDLE (WM_USER + 1)
31 /* internal flags for menu tracking */
33 #define TF_ENDMENU 0x10000
34 #define TF_SUSPENDPOPUP 0x20000
35 #define TF_SKIPREMOVE 0x40000
38 /* maximum allowed depth of any branch in the menu tree.
39 * This value is slightly larger than in windows (25) to
40 * stay on the safe side. */
41 #define MAXMENUDEPTH 30
43 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
45 #define MENUITEMINFO_TYPE_MASK \
46 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
47 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
48 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
50 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
52 #define STATE_MASK (~TYPE_MASK)
54 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
56 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
58 #define IS_SYSTEM_MENU(MenuInfo) \
59 (!((MenuInfo)->fFlags & MNF_POPUP) && ((MenuInfo)->fFlags & MNF_SYSMENU))
61 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
63 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
64 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
66 /* Maximum number of menu items a menu can contain */
67 #define MAX_MENU_ITEMS (0x4000)
68 #define MAX_GOINTOSUBMENU (0x10)
70 /* Space between 2 columns */
71 #define MENU_COL_SPACE 4
73 /* top and bottom margins for popup menus */
74 #define MENU_TOP_MARGIN 2 //3
75 #define MENU_BOTTOM_MARGIN 2
77 #define MENU_ITEM_HBMP_SPACE (5)
78 #define MENU_BAR_ITEMS_SPACE (12)
79 #define SEPARATOR_HEIGHT (5)
80 #define MENU_TAB_SPACE (8)
85 PMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
86 PMENU TopMenu
; /* initial menu */
87 PWND OwnerWnd
; /* where notifications are sent */
91 /* Internal MenuTrackMenu() flags */
92 #define TPM_INTERNAL 0xF0000000
93 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
94 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
99 #define UpdateMenuItemState(state, change) \
101 if((change) & MF_GRAYED) { \
102 (state) |= MF_GRAYED; \
104 (state) &= ~MF_GRAYED; \
105 } /* Separate the two for test_menu_resource_layout.*/ \
106 if((change) & MF_DISABLED) { \
107 (state) |= MF_DISABLED; \
109 (state) &= ~MF_DISABLED; \
111 if((change) & MFS_CHECKED) { \
112 (state) |= MFS_CHECKED; \
114 (state) &= ~MFS_CHECKED; \
116 if((change) & MFS_HILITE) { \
117 (state) |= MFS_HILITE; \
119 (state) &= ~MFS_HILITE; \
121 if((change) & MFS_DEFAULT) { \
122 (state) |= MFS_DEFAULT; \
124 (state) &= ~MFS_DEFAULT; \
126 if((change) & MF_MOUSESELECT) { \
127 (state) |= MF_MOUSESELECT; \
129 (state) &= ~MF_MOUSESELECT; \
135 DumpMenuItemList(PMENU Menu
, PITEM MenuItem
)
137 UINT cnt
= 0, i
= Menu
->cItems
;
140 if(MenuItem
->lpstr
.Length
)
141 DbgPrint(" %d. %wZ\n", ++cnt
, &MenuItem
->lpstr
);
143 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt
, (DWORD
)MenuItem
->lpstr
.Buffer
);
145 if(MFT_BITMAP
& MenuItem
->fType
)
146 DbgPrint("MFT_BITMAP ");
147 if(MFT_MENUBARBREAK
& MenuItem
->fType
)
148 DbgPrint("MFT_MENUBARBREAK ");
149 if(MFT_MENUBREAK
& MenuItem
->fType
)
150 DbgPrint("MFT_MENUBREAK ");
151 if(MFT_OWNERDRAW
& MenuItem
->fType
)
152 DbgPrint("MFT_OWNERDRAW ");
153 if(MFT_RADIOCHECK
& MenuItem
->fType
)
154 DbgPrint("MFT_RADIOCHECK ");
155 if(MFT_RIGHTJUSTIFY
& MenuItem
->fType
)
156 DbgPrint("MFT_RIGHTJUSTIFY ");
157 if(MFT_SEPARATOR
& MenuItem
->fType
)
158 DbgPrint("MFT_SEPARATOR ");
159 if(MFT_STRING
& MenuItem
->fType
)
160 DbgPrint("MFT_STRING ");
161 DbgPrint("\n fState=");
162 if(MFS_DISABLED
& MenuItem
->fState
)
163 DbgPrint("MFS_DISABLED ");
165 DbgPrint("MFS_ENABLED ");
166 if(MFS_CHECKED
& MenuItem
->fState
)
167 DbgPrint("MFS_CHECKED ");
169 DbgPrint("MFS_UNCHECKED ");
170 if(MFS_HILITE
& MenuItem
->fState
)
171 DbgPrint("MFS_HILITE ");
173 DbgPrint("MFS_UNHILITE ");
174 if(MFS_DEFAULT
& MenuItem
->fState
)
175 DbgPrint("MFS_DEFAULT ");
176 if(MFS_GRAYED
& MenuItem
->fState
)
177 DbgPrint("MFS_GRAYED ");
178 DbgPrint("\n wId=%d\n", MenuItem
->wID
);
182 DbgPrint("Entries: %d\n", cnt
);
187 #define FreeMenuText(Menu,MenuItem) \
189 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
190 (MenuItem)->lpstr.Length) { \
191 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
196 IntGetMenuObject(HMENU hMenu
)
198 PMENU Menu
= UserGetMenuObject(hMenu
);
200 Menu
->head
.cLockObj
++;
205 PMENU FASTCALL
VerifyMenu(PMENU pMenu
)
211 if (!pMenu
) return NULL
;
213 Error
= EngGetLastError();
217 hMenu
= UserHMGetHandle(pMenu
);
218 pItem
= pMenu
->rgItems
;
225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
227 ERR("Run away LOOP!\n");
228 EngSetLastError(Error
);
229 _SEH2_YIELD(return NULL
);
233 if ( UserObjectInDestroy(hMenu
))
235 ERR("Menu is marked for destruction!\n");
238 EngSetLastError(Error
);
244 IntIsMenu(HMENU Menu
)
246 if (UserGetMenuObject(Menu
)) return TRUE
;
252 IntGetMenu(HWND hWnd
)
254 PWND Wnd
= ValidateHwndNoErr(hWnd
);
259 return UserGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
262 PMENU
get_win_sys_menu( HWND hwnd
)
265 WND
*win
= ValidateHwndNoErr( hwnd
);
268 ret
= UserGetMenuObject(win
->SystemMenu
);
273 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
)
277 if (pMenu
->rgItems
) /* recursively destroy submenus */
280 ITEM
*item
= pMenu
->rgItems
;
281 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
283 SubMenu
= item
->spSubMenu
;
284 item
->spSubMenu
= NULL
;
286 /* Remove Item Text */
287 FreeMenuText(pMenu
,item
);
289 /* Remove Item Bitmap and set it for this process */
290 if (item
->hbmp
&& !(item
->fState
& MFS_HBMMENUBMP
))
292 GreSetObjectOwner(item
->hbmp
, GDI_OBJ_HMGR_POWNED
);
296 /* Remove Item submenu */
297 if (bRecurse
&& SubMenu
)//VerifyMenu(SubMenu))
299 /* Release submenu since it was referenced when inserted */
300 IntReleaseMenuObject(SubMenu
);
301 IntDestroyMenuObject(SubMenu
, bRecurse
);
305 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
306 pMenu
->rgItems
= NULL
;
312 /* Callback for the object manager */
314 UserDestroyMenuObject(PVOID Object
)
316 return IntDestroyMenuObject(Object
, TRUE
);
320 IntDestroyMenuObject(PMENU Menu
, BOOL bRecurse
)
326 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
331 Window
= ValidateHwndNoErr(Menu
->hWnd
);
334 //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
336 /* DestroyMenu should not destroy system menu popup owner */
337 if ((Menu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
)
339 // Should we check it to see if it has Class?
340 ERR("FIXME Pop up menu window thing'ie\n");
341 //co_UserDestroyWindow( Window );
347 if (!UserMarkObjectDestroy(Menu
)) return TRUE
;
349 /* Remove all menu items */
350 IntDestroyMenu( Menu
, bRecurse
);
352 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
353 TRACE("IntDestroyMenuObject %d\n",ret
);
363 NONCLIENTMETRICSW ncm
;
365 /* get the menu font */
366 if (!ghMenuFont
|| !ghMenuFontBold
)
368 ncm
.cbSize
= sizeof(ncm
);
369 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
371 ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
375 ghMenuFont
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
376 if (ghMenuFont
== NULL
)
378 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
381 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
382 ghMenuFontBold
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
383 if (ghMenuFontBold
== NULL
)
385 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
386 GreDeleteObject(ghMenuFont
);
391 GreSetObjectOwner(ghMenuFont
, GDI_OBJ_HMGR_PUBLIC
);
392 GreSetObjectOwner(ghMenuFontBold
, GDI_OBJ_HMGR_PUBLIC
);
401 /**********************************************************************
404 * detect if there are loops in the menu tree (or the depth is too large)
406 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
412 if (!pmenu
) return depth
;
415 if( depth
> MAXMENUDEPTH
) return depth
;
416 item
= pmenu
->rgItems
;
418 for( i
= 0; i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
420 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
422 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
423 if( bdepth
> subdepth
) subdepth
= bdepth
;
425 if( subdepth
> MAXMENUDEPTH
)
426 TRACE("<- hmenu %p\n", item
->spSubMenu
);
432 /******************************************************************************
434 * UINT MenuGetStartOfNextColumn(
437 *****************************************************************************/
439 static UINT
MENU_GetStartOfNextColumn(
446 return NO_SELECTED_ITEM
;
449 if( i
== NO_SELECTED_ITEM
)
452 pItem
= menu
->rgItems
;
453 if (!pItem
) return NO_SELECTED_ITEM
;
455 for( ; i
< menu
->cItems
; ++i
) {
456 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
460 return NO_SELECTED_ITEM
;
463 /******************************************************************************
465 * UINT MenuGetStartOfPrevColumn(
468 *****************************************************************************/
469 static UINT
MENU_GetStartOfPrevColumn(
476 return NO_SELECTED_ITEM
;
478 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
479 return NO_SELECTED_ITEM
;
481 pItem
= menu
->rgItems
;
482 if (!pItem
) return NO_SELECTED_ITEM
;
484 /* Find the start of the column */
486 for(i
= menu
->iItem
; i
!= 0 &&
487 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
491 return NO_SELECTED_ITEM
;
493 for(--i
; i
!= 0; --i
) {
494 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
498 TRACE("ret %d.\n", i
);
503 /***********************************************************************
506 * Find a menu item. Return a pointer on the item, and modifies *hmenu
507 * in case the item was in a sub-menu.
509 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
512 ITEM
*fallback
= NULL
;
513 UINT fallback_pos
= 0;
516 if (!menu
) return NULL
;
518 if (wFlags
& MF_BYPOSITION
)
520 if (!menu
->cItems
) return NULL
;
521 if (*nPos
>= menu
->cItems
) return NULL
;
522 return &menu
->rgItems
[*nPos
];
526 PITEM item
= menu
->rgItems
;
527 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
531 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
532 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
538 else if (item
->wID
== *nPos
)
540 /* fallback to this item if nothing else found */
545 else if (item
->wID
== *nPos
)
554 *nPos
= fallback_pos
;
559 /***********************************************************************
562 * Find a Sub menu. Return the position of the submenu, and modifies
563 * *hmenu in case it is found in another sub-menu.
564 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
566 static UINT FASTCALL
MENU_FindSubMenu(PMENU
*menu
, PMENU SubTarget
)
571 item
= ((PMENU
)*menu
)->rgItems
;
572 for (i
= 0; i
< ((PMENU
)*menu
)->cItems
; i
++, item
++)
574 if (!item
->spSubMenu
)
578 if (item
->spSubMenu
== SubTarget
)
584 PMENU pSubMenu
= item
->spSubMenu
;
585 UINT pos
= MENU_FindSubMenu( &pSubMenu
, SubTarget
);
586 if (pos
!= NO_SELECTED_ITEM
)
594 return NO_SELECTED_ITEM
;
598 IntRemoveMenuItem( PMENU pMenu
, UINT nPos
, UINT wFlags
, BOOL bRecurse
)
603 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
604 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
608 FreeMenuText(pMenu
,item
);
609 if (bRecurse
&& item
->spSubMenu
)
611 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
);
613 ////// Use cAlloced with inc's of 8's....
614 if (--pMenu
->cItems
== 0)
616 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
617 pMenu
->rgItems
= NULL
;
621 while (nPos
< pMenu
->cItems
)
627 newItems
= DesktopHeapReAlloc(pMenu
->head
.rpdesk
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
630 pMenu
->rgItems
= newItems
;
636 /**********************************************************************
639 * Insert (allocate) a new item into a menu.
641 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
645 /* Find where to insert new item */
647 if (flags
& MF_BYPOSITION
) {
648 if (pos
> menu
->cItems
)
651 if (!MENU_FindItem( &menu
, &pos
, flags
))
653 if (submenu
) *submenu
= menu
;
654 if (npos
) *npos
= pos
;
659 /* Make sure that MDI system buttons stay on the right side.
660 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
661 * regardless of their id.
664 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
665 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
668 TRACE("inserting at %u flags %x\n", pos
, flags
);
670 /* Create new items array */
672 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
675 WARN("allocation failed\n" );
678 if (menu
->cItems
> 0)
680 /* Copy the old array into the new one */
681 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
682 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
683 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
685 menu
->rgItems
= newItems
;
687 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
688 menu
->cyMenu
= 0; /* force size recalculate */
689 return &newItems
[pos
];
694 _In_ PMENU MenuObject
,
697 PROSMENUITEMINFO ItemInfo
,
698 PUNICODE_STRING lpstr
)
701 PMENU SubMenu
= NULL
;
703 NT_ASSERT(MenuObject
!= NULL
);
705 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
707 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
711 SubMenu
= MenuObject
;
713 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
715 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
717 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
721 /* Force size recalculation! */
723 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
725 TRACE("IntInsertMenuItemToList = %u %i\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
732 _Out_ PHANDLE Handle
,
734 _In_ PDESKTOP Desktop
,
735 _In_ PPROCESSINFO ppi
)
739 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
751 Menu
->cyMax
= 0; /* Default */
752 Menu
->hbrBack
= NULL
; /* No brush */
753 Menu
->dwContextHelpId
= 0; /* Default */
754 Menu
->dwMenuData
= 0; /* Default */
755 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
756 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
757 Menu
->spwndNotify
= NULL
;
758 Menu
->cyMenu
= 0; // Height
759 Menu
->cxMenu
= 0; // Width
760 Menu
->cItems
= 0; // Item count
763 Menu
->cxTextAlign
= 0;
764 Menu
->rgItems
= NULL
;
767 Menu
->TimeToHide
= FALSE
;
773 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
775 PITEM MenuItem
, NewMenuItem
= NULL
;
781 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, Source
->cItems
* sizeof(ITEM
));
782 if(!NewMenuItem
) return FALSE
;
784 RtlZeroMemory(NewMenuItem
, Source
->cItems
* sizeof(ITEM
));
786 Destination
->rgItems
= NewMenuItem
;
788 MenuItem
= Source
->rgItems
;
789 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
791 NewMenuItem
->fType
= MenuItem
->fType
;
792 NewMenuItem
->fState
= MenuItem
->fState
;
793 NewMenuItem
->wID
= MenuItem
->wID
;
794 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
795 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
796 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
797 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
798 if (MenuItem
->lpstr
.Length
)
800 NewMenuItem
->lpstr
.Length
= 0;
801 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
802 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
803 if (!NewMenuItem
->lpstr
.Buffer
)
805 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
808 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
809 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
810 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
814 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
815 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
817 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
818 Destination
->cItems
= i
+ 1;
824 IntCloneMenu(PMENU Source
)
832 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
833 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
835 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
842 Menu
->fFlags
= Source
->fFlags
;
843 Menu
->cyMax
= Source
->cyMax
;
844 Menu
->hbrBack
= Source
->hbrBack
;
845 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
846 Menu
->dwMenuData
= Source
->dwMenuData
;
847 Menu
->iItem
= NO_SELECTED_ITEM
;
848 Menu
->spwndNotify
= NULL
;
854 Menu
->cxTextAlign
= 0;
855 Menu
->rgItems
= NULL
;
858 Menu
->TimeToHide
= FALSE
;
860 IntCloneMenuItems(Menu
, Source
);
866 IntSetMenuFlagRtoL(PMENU Menu
)
868 ERR("SetMenuFlagRtoL\n");
869 Menu
->fFlags
|= MNF_RTOL
;
874 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
876 Menu
->dwContextHelpId
= dwContextHelpId
;
881 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
883 if(lpmi
->fMask
& MIM_BACKGROUND
)
884 lpmi
->hbrBack
= Menu
->hbrBack
;
885 if(lpmi
->fMask
& MIM_HELPID
)
886 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
887 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
888 lpmi
->cyMax
= Menu
->cyMax
;
889 if(lpmi
->fMask
& MIM_MENUDATA
)
890 lpmi
->dwMenuData
= Menu
->dwMenuData
;
891 if(lpmi
->fMask
& MIM_STYLE
)
892 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
894 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
896 lpmi
->cItems
= Menu
->cItems
;
898 lpmi
->iItem
= Menu
->iItem
;
899 lpmi
->cxMenu
= Menu
->cxMenu
;
900 lpmi
->cyMenu
= Menu
->cyMenu
;
901 lpmi
->spwndNotify
= Menu
->spwndNotify
;
902 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
903 lpmi
->iTop
= Menu
->iTop
;
904 lpmi
->iMaxTop
= Menu
->iMaxTop
;
905 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
907 lpmi
->fFlags
= Menu
->fFlags
;
908 lpmi
->Self
= Menu
->head
.h
;
909 lpmi
->TimeToHide
= Menu
->TimeToHide
;
910 lpmi
->Wnd
= Menu
->hWnd
;
916 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
918 if(lpmi
->fMask
& MIM_BACKGROUND
)
919 Menu
->hbrBack
= lpmi
->hbrBack
;
920 if(lpmi
->fMask
& MIM_HELPID
)
921 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
922 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
923 Menu
->cyMax
= lpmi
->cyMax
;
924 if(lpmi
->fMask
& MIM_MENUDATA
)
925 Menu
->dwMenuData
= lpmi
->dwMenuData
;
926 if(lpmi
->fMask
& MIM_STYLE
)
927 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
928 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
931 PITEM item
= Menu
->rgItems
;
932 for ( i
= Menu
->cItems
; i
; i
--, item
++)
934 if ( item
->spSubMenu
)
936 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
940 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
942 Menu
->iItem
= lpmi
->iItem
;
943 Menu
->cyMenu
= lpmi
->cyMenu
;
944 Menu
->cxMenu
= lpmi
->cxMenu
;
945 Menu
->spwndNotify
= lpmi
->spwndNotify
;
946 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
947 Menu
->iTop
= lpmi
->iTop
;
948 Menu
->iMaxTop
= lpmi
->iMaxTop
;
949 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
951 Menu
->TimeToHide
= lpmi
->TimeToHide
;
952 Menu
->hWnd
= lpmi
->Wnd
;
954 if ( lpmi
->fMask
& MIM_STYLE
)
956 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
957 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
958 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
964 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
965 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
969 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
971 lpmii
->fType
= MenuItem
->fType
;
973 if(lpmii
->fMask
& MIIM_BITMAP
)
975 lpmii
->hbmpItem
= MenuItem
->hbmp
;
977 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
979 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
980 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
982 if(lpmii
->fMask
& MIIM_DATA
)
984 lpmii
->dwItemData
= MenuItem
->dwItemData
;
986 if(lpmii
->fMask
& MIIM_ID
)
988 lpmii
->wID
= MenuItem
->wID
;
990 if(lpmii
->fMask
& MIIM_STATE
)
992 lpmii
->fState
= MenuItem
->fState
;
994 if(lpmii
->fMask
& MIIM_SUBMENU
)
996 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
999 if ((lpmii
->fMask
& MIIM_STRING
) ||
1000 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1002 if (lpmii
->dwTypeData
== NULL
)
1004 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1007 { //// lpmii->lpstr can be read in user mode!!!!
1008 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1009 min(lpmii
->cch
* sizeof(WCHAR
),
1010 MenuItem
->lpstr
.MaximumLength
));
1011 if (! NT_SUCCESS(Status
))
1013 SetLastNtError(Status
);
1019 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1021 lpmii
->Rect
.left
= MenuItem
->xItem
;
1022 lpmii
->Rect
.top
= MenuItem
->yItem
;
1023 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1024 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1025 lpmii
->dxTab
= MenuItem
->dxTab
;
1026 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1027 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1028 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1035 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1037 PMENU SubMenuObject
;
1038 BOOL circref
= FALSE
;
1040 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1044 if ( lpmii
->fMask
& MIIM_FTYPE
)
1046 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1047 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1049 if (lpmii
->fMask
& MIIM_TYPE
)
1051 #if 0 //// Done in User32.
1052 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1054 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1055 KeRosDumpStackFrames(NULL
, 20);
1056 /* This does not happen on Win9x/ME */
1057 SetLastNtError( ERROR_INVALID_PARAMETER
);
1062 * Delete the menu item type when changing type from
1065 if (MenuItem
->fType
!= lpmii
->fType
&&
1066 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1068 FreeMenuText(MenuObject
,MenuItem
);
1069 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1070 MenuItem
->Xlpstr
= NULL
;
1072 if(lpmii
->fType
& MFT_BITMAP
)
1075 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1077 { /* Win 9x/Me stuff */
1078 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1080 lpmii
->dwTypeData
= 0;
1083 if(lpmii
->fMask
& MIIM_BITMAP
)
1085 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1086 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1087 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1089 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1091 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1093 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1094 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1096 if(lpmii
->fMask
& MIIM_DATA
)
1098 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1100 if(lpmii
->fMask
& MIIM_ID
)
1102 MenuItem
->wID
= lpmii
->wID
;
1104 if(lpmii
->fMask
& MIIM_STATE
)
1106 /* Remove MFS_DEFAULT flag from all other menu items if this item
1107 has the MFS_DEFAULT state */
1108 if(lpmii
->fState
& MFS_DEFAULT
)
1109 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1110 /* Update the menu item state flags */
1111 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1114 if(lpmii
->fMask
& MIIM_SUBMENU
)
1116 if (lpmii
->hSubMenu
)
1118 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1119 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1121 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1123 if (MenuObject
== SubMenuObject
)
1126 ERR("Pop Up Menu Double Trouble!\n");
1127 SubMenuObject
= IntCreateMenu(&hMenu
,
1129 MenuObject
->head
.rpdesk
,
1130 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1131 if (!SubMenuObject
) return FALSE
;
1132 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1135 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1137 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1138 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1141 /* Make sure the submenu is marked as a popup menu */
1142 SubMenuObject
->fFlags
|= MNF_POPUP
;
1143 // Now fix the test_subpopup_locked_by_menu tests....
1144 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1145 MenuItem
->spSubMenu
= SubMenuObject
;
1146 UserReferenceObject(SubMenuObject
);
1150 EngSetLastError( ERROR_INVALID_PARAMETER
);
1155 { // If submenu just dereference it.
1156 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1157 MenuItem
->spSubMenu
= NULL
;
1161 if ((lpmii
->fMask
& MIIM_STRING
) ||
1162 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1164 /* free the string when used */
1165 FreeMenuText(MenuObject
,MenuItem
);
1166 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1167 MenuItem
->Xlpstr
= NULL
;
1169 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1171 UNICODE_STRING Source
;
1173 if (!NT_VERIFY(lpmii
->cch
<= UNICODE_STRING_MAX_CHARS
))
1178 Source
.Length
= Source
.MaximumLength
= (USHORT
)(lpmii
->cch
* sizeof(WCHAR
));
1179 Source
.Buffer
= lpmii
->dwTypeData
;
1181 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1182 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1184 MenuItem
->lpstr
.Length
= 0;
1185 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1186 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1187 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1189 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1190 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1195 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1196 !MenuItem
->Xlpstr
&&
1197 !lpmii
->dwTypeData
&&
1198 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1200 MenuItem
->fType
|= MFT_SEPARATOR
;
1202 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1204 MenuItem
->xItem
= lpmii
->Rect
.left
;
1205 MenuItem
->yItem
= lpmii
->Rect
.top
;
1206 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1207 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1208 MenuItem
->dxTab
= lpmii
->dxTab
;
1209 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1210 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1211 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1219 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1224 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1226 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1228 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1230 /* If the close item in the system menu change update the close button */
1233 switch (MenuItem
->wID
) // More than just close.
1241 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1243 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1245 /* Refresh the frame to reflect the change */
1246 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1248 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1251 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1261 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1266 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1268 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1270 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1276 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1279 PITEM MenuItem
= MenuObject
->rgItems
;
1281 if (!MenuItem
) return FALSE
;
1283 /* reset all default-item flags */
1284 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1286 MenuItem
->fState
&= ~MFS_DEFAULT
;
1289 /* no default item */
1290 if(uItem
== (UINT
)-1)
1294 MenuItem
= MenuObject
->rgItems
;
1297 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1298 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1303 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1305 if (MenuItem
->wID
== uItem
)
1307 MenuItem
->fState
|= MFS_DEFAULT
;
1317 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1320 PITEM MenuItem
= MenuObject
->rgItems
;
1323 if (!MenuItem
) return -1;
1325 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1328 if (i
>= MenuObject
->cItems
) return -1;
1331 /* default: don't return disabled items */
1332 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1334 /* search rekursiv when needed */
1335 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1339 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1341 if ( -1 != ret
) return ret
;
1343 /* when item not found in submenu, return the popup item */
1345 return ( fByPos
) ? i
: MenuItem
->wID
;
1355 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1356 return pItem
->spSubMenu
;
1359 /***********************************************************************
1360 * MenuInitSysMenuPopup
1362 * Grey the appropriate items in System menu.
1364 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1369 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1370 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1371 gray
= ((style
& WS_MAXIMIZE
) != 0);
1372 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1373 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1374 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1375 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1376 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1377 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1378 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1379 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1381 /* The menu item must keep its state if it's disabled */
1383 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1385 /* Set default menu item */
1386 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1387 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1388 else DefItem
= SC_CLOSE
;
1390 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1394 /***********************************************************************
1395 * MenuDrawPopupGlyph
1397 * Draws popup magic glyphs (can be found in system menu).
1399 static void FASTCALL
1400 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1403 HFONT hFont
, hOldFont
;
1409 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1412 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1415 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1418 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1422 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1425 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1426 RECTL_vInflateRect(r
, -2, -2);
1427 lf
.lfHeight
= r
->bottom
- r
->top
;
1429 lf
.lfWeight
= FW_NORMAL
;
1430 lf
.lfCharSet
= DEFAULT_CHARSET
;
1431 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1432 hFont
= GreCreateFontIndirectW(&lf
);
1433 /* save font and text color */
1434 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1435 clrsave
= GreGetTextColor(dc
);
1436 bkmode
= GreGetBkMode(dc
);
1437 /* set color and drawing mode */
1438 IntGdiSetBkMode(dc
, TRANSPARENT
);
1444 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1445 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1448 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1449 /* draw selected symbol */
1450 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1451 /* restore previous settings */
1452 IntGdiSetTextColor(dc
, clrsave
);
1453 NtGdiSelectFont(dc
, hOldFont
);
1454 IntGdiSetBkMode(dc
, bkmode
);
1455 GreDeleteObject(hFont
);
1458 /***********************************************************************
1459 * MENU_AdjustMenuItemRect
1461 * Adjust menu item rectangle according to scrolling state.
1464 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1466 if (menu
->dwArrowsOn
)
1468 UINT arrow_bitmap_height
;
1469 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1470 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1471 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1475 /***********************************************************************
1476 * MENU_FindItemByCoords
1478 * Find the item at the specified coordinates (screen coords). Does
1479 * not work for child windows and therefore should not be called for
1480 * an arbitrary system menu.
1482 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1487 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1489 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1490 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1491 pt
.x
= rect
.right
- 1 - pt
.x
;
1495 item
= menu
->rgItems
;
1496 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1498 //rect = item->rect;
1499 rect
.left
= item
->xItem
;
1500 rect
.top
= item
->yItem
;
1501 rect
.right
= item
->cxItem
; // Do this for now......
1502 rect
.bottom
= item
->cyItem
;
1504 MENU_AdjustMenuItemRect(menu
, &rect
);
1505 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1514 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1516 MENU
*menu
= UserGetMenuObject(hMenu
);
1519 /*FIXME: Do we have to handle hWnd here? */
1520 if (!menu
) return -1;
1521 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1525 /***********************************************************************
1528 * Find the menu item selected by a key press.
1529 * Return item id, -1 if none, -2 if we should close the menu.
1531 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1532 WCHAR Key
, BOOL ForceMenuChar
)
1537 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1539 if (!menu
|| !VerifyMenu(menu
))
1540 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1543 ITEM
*item
= menu
->rgItems
;
1545 if ( !ForceMenuChar
)
1548 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1550 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1552 LPWSTR text
= item
->Xlpstr
;
1555 const WCHAR
*p
= text
- 2;
1558 const WCHAR
*q
= p
+ 2;
1559 p
= wcschr (q
, '&');
1560 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1562 while (p
!= NULL
&& p
[1] == '&');
1563 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1568 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1569 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1571 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1572 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1573 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1574 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1579 /***********************************************************************
1580 * MenuGetBitmapItemSize
1582 * Get the size of a bitmap item.
1584 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1587 HBITMAP bmp
= lpitem
->hbmp
;
1589 size
->cx
= size
->cy
= 0;
1591 /* check if there is a magic menu item associated with this item */
1592 if (IS_MAGIC_BITMAP(bmp
))
1594 switch((INT_PTR
) bmp
)
1596 case (INT_PTR
)HBMMENU_CALLBACK
:
1598 MEASUREITEMSTRUCT measItem
;
1599 measItem
.CtlType
= ODT_MENU
;
1601 measItem
.itemID
= lpitem
->wID
;
1602 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1603 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1604 measItem
.itemData
= lpitem
->dwItemData
;
1605 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1606 size
->cx
= measItem
.itemWidth
;
1607 size
->cy
= measItem
.itemHeight
;
1608 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1613 case (INT_PTR
) HBMMENU_SYSTEM
:
1614 if (lpitem
->dwItemData
)
1616 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1620 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1621 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1622 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1623 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1624 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1625 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1626 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1627 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1628 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1629 /* FIXME: Why we need to subtract these magic values? */
1630 /* to make them smaller than the menu bar? */
1631 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1632 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1637 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1639 size
->cx
= bm
.bmWidth
;
1640 size
->cy
= bm
.bmHeight
;
1644 /***********************************************************************
1645 * MenuDrawBitmapItem
1647 * Draw a bitmap item.
1649 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1650 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1656 int w
= rect
->right
- rect
->left
;
1657 int h
= rect
->bottom
- rect
->top
;
1658 int bmp_xoffset
= 0;
1661 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1664 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1666 /* Check if there is a magic menu item associated with this item */
1667 if (IS_MAGIC_BITMAP(hbmToDraw
))
1673 switch ((INT_PTR
)hbmToDraw
)
1675 case (INT_PTR
)HBMMENU_SYSTEM
:
1676 if (lpitem
->dwItemData
)
1678 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1680 ERR("Get Item Data from this Window!!!\n");
1683 ERR("Draw Bitmap\n");
1684 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1685 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1689 PCURICON_OBJECT pIcon
= NULL
;
1690 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1692 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1693 /* only use right half of the bitmap */
1694 //bmp_xoffset = bm.bmWidth / 2;
1695 //bm.bmWidth -= bmp_xoffset;
1698 pIcon
= NC_IconForWindow(WndOwner
);
1699 // FIXME: NC_IconForWindow should reference it for us */
1700 if (pIcon
) UserReferenceObject(pIcon
);
1705 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1706 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1707 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1708 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1709 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1710 UserDereferenceObject(pIcon
);
1715 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1716 flags
= DFCS_CAPTIONRESTORE
;
1718 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1720 flags
= DFCS_CAPTIONMIN
;
1722 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1724 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1726 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1727 flags
= DFCS_CAPTIONCLOSE
;
1729 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1730 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1732 case (INT_PTR
)HBMMENU_CALLBACK
:
1734 DRAWITEMSTRUCT drawItem
;
1736 drawItem
.CtlType
= ODT_MENU
;
1738 drawItem
.itemID
= lpitem
->wID
;
1739 drawItem
.itemAction
= odaction
;
1740 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1741 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1742 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1743 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1744 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1745 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1746 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1747 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1749 drawItem
.rcItem
= *rect
;
1750 drawItem
.itemData
= lpitem
->dwItemData
;
1751 /* some applications make this assumption on the DC's origin */
1752 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1753 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1754 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1755 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1760 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1761 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1762 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1763 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1764 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1767 RECTL_vInflateRect(&r
, -1, -1);
1768 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1769 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1773 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1776 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1777 NtGdiSelectBitmap( hdcMem
, bmp
);
1778 /* handle fontsize > bitmap_height */
1779 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1781 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1782 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1783 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1786 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
1791 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1792 IntGdiDeleteDC( hdcMem
, FALSE
);
1796 IntGetDialogBaseUnits(VOID
)
1805 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1807 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1808 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1809 UserReleaseDC( 0, hdc
, FALSE
);
1816 /***********************************************************************
1819 * Calculate the size of the menu item and store it in lpitem->rect.
1821 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1822 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1825 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1826 UINT arrow_bitmap_width
;
1830 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1832 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1834 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1836 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1838 if (lpitem
->fType
& MF_OWNERDRAW
)
1840 MEASUREITEMSTRUCT mis
;
1841 mis
.CtlType
= ODT_MENU
;
1843 mis
.itemID
= lpitem
->wID
;
1844 mis
.itemData
= lpitem
->dwItemData
;
1845 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1847 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1848 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1849 * width of a menufont character to the width of an owner-drawn menu.
1851 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1853 /* under at least win95 you seem to be given a standard
1854 height for the menu and the height value is ignored */
1855 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1857 Rect
.bottom
+= mis
.itemHeight
;
1859 //lpitem->cxBmp = mis.itemWidth;
1860 //lpitem->cyBmp = mis.itemHeight;
1861 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1862 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1863 lpitem
->wID
, Rect
.right
-Rect
.left
,
1864 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1866 lpitem
->xItem
= Rect
.left
;
1867 lpitem
->yItem
= Rect
.top
;
1868 lpitem
->cxItem
= Rect
.right
;
1869 lpitem
->cyItem
= Rect
.bottom
;
1874 lpitem
->xItem
= orgX
;
1875 lpitem
->yItem
= orgY
;
1876 lpitem
->cxItem
= orgX
;
1877 lpitem
->cyItem
= orgY
;
1879 if (lpitem
->fType
& MF_SEPARATOR
)
1881 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1883 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1894 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1895 /* Keep the size of the bitmap in callback mode to be able
1896 * to draw it correctly */
1897 lpitem
->cxBmp
= size
.cx
;
1898 lpitem
->cyBmp
= size
.cy
;
1899 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1900 lpitem
->cxItem
+= size
.cx
+ 2;
1901 itemheight
= size
.cy
+ 2;
1903 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1904 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1905 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1906 lpitem
->dxTab
= lpitem
->cxItem
;
1907 lpitem
->cxItem
+= arrow_bitmap_width
;
1908 } else /* hbmpItem & MenuBar */ {
1909 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1910 lpitem
->cxItem
+= size
.cx
;
1911 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1912 itemheight
= size
.cy
;
1914 /* Special case: Minimize button doesn't have a space behind it. */
1915 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1916 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1917 lpitem
->cxItem
-= 1;
1920 else if (!menuBar
) {
1921 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1922 lpitem
->cxItem
+= check_bitmap_width
;
1923 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1924 lpitem
->dxTab
= lpitem
->cxItem
;
1925 lpitem
->cxItem
+= arrow_bitmap_width
;
1928 /* it must be a text item - unless it's the system menu */
1929 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1930 HFONT hfontOld
= NULL
;
1931 RECT rc
;// = lpitem->Rect;
1932 LONG txtheight
, txtwidth
;
1934 rc
.left
= lpitem
->xItem
;
1935 rc
.top
= lpitem
->yItem
;
1936 rc
.right
= lpitem
->cxItem
; // Do this for now......
1937 rc
.bottom
= lpitem
->cyItem
;
1939 if ( lpitem
->fState
& MFS_DEFAULT
) {
1940 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1943 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1945 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1946 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1948 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1950 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1953 int n
= (int)( p
- lpitem
->Xlpstr
);
1954 /* Item contains a tab (only meaningful in popup menus) */
1955 /* get text size before the tab */
1956 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1957 DT_SINGLELINE
|DT_CALCRECT
);
1958 txtwidth
= rc
.right
- rc
.left
;
1959 p
+= 1; /* advance past the Tab */
1960 /* get text size after the tab */
1961 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1962 DT_SINGLELINE
|DT_CALCRECT
);
1963 lpitem
->dxTab
+= txtwidth
;
1964 txtheight
= max( txtheight
, tmpheight
);
1965 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1966 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1968 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1969 DT_SINGLELINE
|DT_CALCRECT
);
1970 txtwidth
= rc
.right
- rc
.left
;
1971 lpitem
->dxTab
+= txtwidth
;
1973 lpitem
->cxItem
+= 2 + txtwidth
;
1974 itemheight
= max( itemheight
,
1975 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1979 NtGdiSelectFont (hdc
, hfontOld
);
1981 } else if( menuBar
) {
1982 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1984 lpitem
->cyItem
+= itemheight
;
1985 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1988 /***********************************************************************
1989 * MENU_GetMaxPopupHeight
1992 MENU_GetMaxPopupHeight(PMENU lppop
)
1996 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1997 return lppop
->cyMax
;
1999 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
2000 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
2003 /***********************************************************************
2004 * MenuPopupMenuCalcSize
2006 * Calculate the size of a popup menu.
2008 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
2013 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
2014 BOOL textandbmp
= FALSE
;
2016 Menu
->cxMenu
= Menu
->cyMenu
= 0;
2017 if (Menu
->cItems
== 0) return;
2019 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2021 NtGdiSelectFont( hdc
, ghMenuFont
);
2026 Menu
->cxTextAlign
= 0;
2028 while (start
< Menu
->cItems
)
2030 lpitem
= &Menu
->rgItems
[start
];
2032 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2033 orgX
+= MENU_COL_SPACE
;
2034 orgY
= MENU_TOP_MARGIN
;
2036 maxTab
= maxTabWidth
= 0;
2037 /* Parse items until column break or end of menu */
2038 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2041 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2043 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2044 maxX
= max(maxX
, lpitem
->cxItem
);
2045 orgY
= lpitem
->cyItem
;
2046 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2048 maxTab
= max( maxTab
, lpitem
->dxTab
);
2049 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2051 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2054 /* Finish the column (set all items to the largest width found) */
2055 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2056 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2058 lpitem
->cxItem
= maxX
;
2059 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2060 lpitem
->dxTab
= maxTab
;
2062 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2065 Menu
->cxMenu
= maxX
;
2066 /* if none of the items have both text and bitmap then
2067 * the text and bitmaps are all aligned on the left. If there is at
2068 * least one item with both text and bitmap then bitmaps are
2069 * on the left and texts left aligned with the right hand side
2071 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2073 /* space for 3d border */
2074 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2077 /* Adjust popup height if it exceeds maximum */
2078 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2079 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2080 if (Menu
->cyMenu
>= maxHeight
)
2082 Menu
->cyMenu
= maxHeight
;
2083 Menu
->dwArrowsOn
= 1;
2087 Menu
->dwArrowsOn
= 0;
2089 UserReleaseDC( 0, hdc
, FALSE
);
2092 /***********************************************************************
2093 * MENU_MenuBarCalcSize
2095 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2096 * height is off by 1 pixel which causes lengthy window relocations when
2097 * active document window is maximized/restored.
2099 * Calculate the size of the menu bar.
2101 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2104 UINT start
, i
, helpPos
;
2105 int orgX
, orgY
, maxY
;
2107 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2108 if (lppop
->cItems
== 0) return;
2109 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2110 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2115 lppop
->cxTextAlign
= 0;
2116 while (start
< lppop
->cItems
)
2118 lpitem
= &lppop
->rgItems
[start
];
2119 orgX
= lprect
->left
;
2122 /* Parse items until line break or end of menu */
2123 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2125 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2127 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2129 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2130 //debug_print_menuitem (" item: ", lpitem, "");
2131 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2132 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2134 if (lpitem
->cxItem
> lprect
->right
)
2136 if (i
!= start
) break;
2137 else lpitem
->cxItem
= lprect
->right
;
2139 maxY
= max( maxY
, lpitem
->cyItem
);
2140 orgX
= lpitem
->cxItem
;
2143 /* Finish the line (set all items to the largest height found) */
2145 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2146 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2148 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2150 start
= i
; /* This works! */
2153 lprect
->bottom
= maxY
+ 1;
2154 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2156 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2157 /* the last item (if several lines, only move the last line) */
2158 if (helpPos
== ~0U) return;
2159 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2160 orgY
= lpitem
->yItem
;
2161 orgX
= lprect
->right
;
2162 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2163 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2164 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2165 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2166 lpitem
->cxItem
= orgX
;
2167 orgX
= lpitem
->xItem
;
2171 /***********************************************************************
2172 * MENU_DrawScrollArrows
2174 * Draw scroll arrows.
2176 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2178 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2182 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2183 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2187 rect
.right
= lppop
->cxMenu
;
2188 rect
.bottom
= arrow_bitmap_height
;
2189 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2190 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2192 dfcrc
.right
= arrow_bitmap_width
;
2193 dfcrc
.bottom
= arrow_bitmap_height
;
2194 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2196 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2197 rect
.bottom
= lppop
->cyMenu
;
2198 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2199 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2200 Flags
= DFCS_INACTIVE
;
2201 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2202 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2203 dfcrc
.right
= arrow_bitmap_width
;
2204 dfcrc
.bottom
= lppop
->cyMenu
;
2205 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2208 /***********************************************************************
2211 * Draw a single menu item.
2213 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2214 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2218 BOOL flat_menu
= FALSE
;
2220 UINT arrow_bitmap_width
= 0;
2224 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2227 if (lpitem
->fType
& MF_SYSMENU
)
2229 if (!(Wnd
->style
& WS_MINIMIZE
))
2231 NC_GetInsideRect(Wnd
, &rect
);
2232 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2237 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2238 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2242 if (lpitem
->fState
& MF_HILITE
)
2244 if(menuBar
&& !flat_menu
) {
2245 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2246 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2248 if (lpitem
->fState
& MF_GRAYED
)
2249 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2251 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2252 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2257 if (lpitem
->fState
& MF_GRAYED
)
2258 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2260 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2261 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2264 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2265 //rect = lpitem->Rect;
2266 rect
.left
= lpitem
->xItem
;
2267 rect
.top
= lpitem
->yItem
;
2268 rect
.right
= lpitem
->cxItem
; // Do this for now......
2269 rect
.bottom
= lpitem
->cyItem
;
2271 MENU_AdjustMenuItemRect(Menu
, &rect
);
2273 if (lpitem
->fType
& MF_OWNERDRAW
)
2276 ** Experimentation under Windows reveals that an owner-drawn
2277 ** menu is given the rectangle which includes the space it requested
2278 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2279 ** and a popup-menu arrow. This is the value of lpitem->rect.
2280 ** Windows will leave all drawing to the application except for
2281 ** the popup-menu arrow. Windows always draws that itself, after
2282 ** the menu owner has finished drawing.
2285 COLORREF old_bk
, old_text
;
2287 dis
.CtlType
= ODT_MENU
;
2289 dis
.itemID
= lpitem
->wID
;
2290 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2292 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2293 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2294 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2295 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2296 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2297 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2298 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2299 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2300 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2303 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2304 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2305 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2306 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2308 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2309 old_bk
= GreGetBkColor(hdc
);
2310 old_text
= GreGetTextColor(hdc
);
2311 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2312 IntGdiSetBkColor(hdc
, old_bk
);
2313 IntGdiSetTextColor(hdc
, old_text
);
2314 /* Draw the popup-menu arrow */
2315 if (!menuBar
&& lpitem
->spSubMenu
)
2318 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2319 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2320 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2325 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2327 if (lpitem
->fState
& MF_HILITE
)
2331 RECTL_vInflateRect (&rect
, -1, -1);
2332 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2333 RECTL_vInflateRect (&rect
, 1, 1);
2334 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2340 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2341 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2345 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2350 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2352 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2354 /* vertical separator */
2355 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2360 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2362 rc
.bottom
= Height
- 3;
2365 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2366 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2367 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2368 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2369 NtGdiSelectPen( hdc
, oldPen
);
2372 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2375 /* horizontal separator */
2376 if (lpitem
->fType
& MF_SEPARATOR
)
2383 rc
.top
= ( rc
.top
+ rc
.bottom
) / 2;
2386 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2387 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2388 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2389 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2390 NtGdiSelectPen( hdc
, oldPen
);
2393 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2397 /* helper lines for debugging */
2398 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2399 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2400 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2401 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2402 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2403 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2405 #if 0 // breaks mdi menu bar icons.
2407 /* calculate the bitmap rectangle in coordinates relative
2408 * to the item rectangle */
2410 if( lpitem
->hbmp
== HBMMENU_CALLBACK
)
2413 bmprc
.left
= lpitem
->Xlpstr
? MenuCharSize
.cx
: 0;
2415 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)
2417 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)
2420 bmprc
.left
= 4 + UserGetSystemMetrics(SM_CXMENUCHECK
);
2422 bmprc
.right
= bmprc
.left
+ lpitem
->cxBmp
;
2424 if( menuBar
&& !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2427 bmprc
.top
= (rect
.bottom
- rect
.top
- lpitem
->cyBmp
) / 2;
2429 bmprc
.bottom
= bmprc
.top
+ lpitem
->cyBmp
;
2435 INT y
= rect
.top
+ rect
.bottom
;
2437 BOOL checked
= FALSE
;
2438 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2439 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2440 /* Draw the check mark
2443 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2445 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2446 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2447 lpitem
->hbmpUnchecked
;
2448 if (bm
) /* we have a custom bitmap */
2450 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2452 NtGdiSelectBitmap( hdcMem
, bm
);
2453 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2454 check_bitmap_width
, check_bitmap_height
,
2455 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2456 IntGdiDeleteDC( hdcMem
, FALSE
);
2459 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2463 r
.right
= r
.left
+ check_bitmap_width
;
2464 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2465 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2466 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2470 if ( lpitem
->hbmp
)//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2472 RECT bmpRect
= rect
;
2473 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2474 bmpRect
.left
+= check_bitmap_width
+ 2;
2475 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2477 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2478 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2481 /* Draw the popup-menu arrow */
2482 if (lpitem
->spSubMenu
)
2485 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2486 rectTemp
.left
= rectTemp
.right
- check_bitmap_width
;
2487 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2490 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2491 rect
.left
+= check_bitmap_width
;
2492 rect
.right
-= arrow_bitmap_width
;
2494 else if( lpitem
->hbmp
)
2495 { /* Draw the bitmap */
2496 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
/*bmprc*/, Menu
, WndOwner
, odaction
, menuBar
);
2499 /* process text if present */
2505 UINT uFormat
= menuBar
?
2506 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2507 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2509 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2510 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2512 rect
.left
+= Menu
->cxTextAlign
;
2514 if ( lpitem
->fState
& MFS_DEFAULT
)
2516 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2521 rect
.left
+= lpitem
->cxBmp
;
2522 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2523 rect
.left
+= MenuCharSize
.cx
;
2524 rect
.right
-= MenuCharSize
.cx
;
2527 Text
= lpitem
->Xlpstr
;
2530 for (i
= 0; Text
[i
]; i
++)
2531 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2537 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
2539 RECTL_vOffsetRect(&rect
, +1, +1);
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
, &rect
, uFormat
);
2549 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2551 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2553 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2555 /* paint the shortcut text */
2556 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2558 if (L
'\t' == Text
[i
])
2560 rect
.left
= lpitem
->dxTab
;
2561 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2565 rect
.right
= lpitem
->dxTab
;
2566 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2569 if (lpitem
->fState
& MF_GRAYED
)
2571 if (!(lpitem
->fState
& MF_HILITE
) )
2573 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2574 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2575 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2576 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2578 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2580 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2585 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
2587 RECTL_vOffsetRect(&rect
, -1, -1);
2592 NtGdiSelectFont (hdc
, hfontOld
);
2597 /***********************************************************************
2600 * Paint a popup menu.
2602 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2604 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2607 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2609 IntGetClientRect( wnd
, &rect
);
2611 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2612 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2613 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2617 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2619 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2622 BOOL flat_menu
= FALSE
;
2624 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2626 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2628 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2630 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2631 /* draw menu items */
2632 if (menu
&& menu
->cItems
)
2637 item
= menu
->rgItems
;
2638 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2640 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2641 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2643 /* draw scroll arrows */
2644 if (menu
->dwArrowsOn
)
2646 MENU_DrawScrollArrows(menu
, hdc
);
2652 NtGdiSelectBrush( hdc
, hPrevBrush
);
2657 /**********************************************************************
2660 PWND
MENU_IsMenuActive(VOID
)
2662 return ValidateHwndNoErr(top_popup
);
2665 /**********************************************************************
2668 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2670 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2672 void MENU_EndMenu( PWND pwnd
)
2675 menu
= UserGetMenuObject(top_popup_hmenu
);
2676 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2678 if (fInsideMenuLoop
&& top_popup
)
2680 fInsideMenuLoop
= FALSE
;
2684 ERR("Already in End loop\n");
2689 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2695 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2698 HFONT FontOld
= NULL
;
2699 BOOL flat_menu
= FALSE
;
2701 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2705 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2713 if (Rect
== NULL
|| !pMenu
)
2715 return UserGetSystemMetrics(SM_CYMENU
);
2718 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2720 FontOld
= NtGdiSelectFont(hDC
, Font
);
2722 if (pMenu
->cyMenu
== 0)
2724 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2727 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2729 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2731 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2732 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2733 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2734 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2736 if (pMenu
->cItems
== 0)
2738 NtGdiSelectFont(hDC
, FontOld
);
2739 return UserGetSystemMetrics(SM_CYMENU
);
2742 for (i
= 0; i
< pMenu
->cItems
; i
++)
2744 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2747 NtGdiSelectFont(hDC
, FontOld
);
2749 return pMenu
->cyMenu
;
2752 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2755 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2759 // No menu. Do not reserve any space
2765 return UserGetSystemMetrics(SM_CYMENU
);
2770 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2772 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2774 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2776 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2778 return lppop
->cyMenu
;
2782 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2786 /***********************************************************************
2789 * Popup menu initialization before WM_ENTERMENULOOP.
2791 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2794 PPOPUPMENU pPopupMenu
;
2796 LARGE_STRING WindowName
;
2797 UNICODE_STRING ClassName
;
2798 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2800 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2802 menu
->spwndNotify
= pWndOwner
;
2804 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2805 ex_style
= WS_EX_LAYOUTRTL
;
2807 ClassName
.Buffer
= WC_MENU
;
2808 ClassName
.Length
= 0;
2810 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2811 RtlZeroMemory(&Cs
, sizeof(Cs
));
2812 Cs
.style
= WS_POPUP
;
2813 Cs
.dwExStyle
= ex_style
;
2814 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2815 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2816 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2817 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2818 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2820 /* NOTE: In Windows, top menu popup is not owned. */
2821 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2823 if( !pWndCreated
) return FALSE
;
2826 // Setup pop up menu structure.
2828 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2830 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2832 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2833 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2834 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2836 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2837 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2838 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2839 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2840 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2842 if (pPopupMenu
->fRightButton
)
2843 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2845 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2847 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2848 menu
->fFlags
& MNF_RTOL
)
2850 pPopupMenu
->fDroppedLeft
= TRUE
;
2855 /***********************************************************************
2858 * Display a popup menu.
2860 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2861 INT x
, INT y
, INT xanchor
, INT yanchor
)
2867 USER_REFERENCE_ENTRY Ref
;
2869 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2870 pwndOwner
, menu
, id
, x
, y
, xanchor
, yanchor
);
2872 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2874 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2875 menu
->iItem
= NO_SELECTED_ITEM
;
2878 menu
->dwArrowsOn
= 0;
2879 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2881 /* adjust popup menu pos so that it fits within the desktop */
2883 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2884 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2886 /* FIXME: should use item rect */
2889 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2891 if (flags
& TPM_LAYOUTRTL
)
2892 flags
^= TPM_RIGHTALIGN
;
2894 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2895 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2897 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2898 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2900 if( x
+ width
> monitor
->rcMonitor
.right
)
2902 if( xanchor
&& x
>= width
- xanchor
)
2903 x
-= width
- xanchor
;
2905 if( x
+ width
> monitor
->rcMonitor
.right
)
2906 x
= monitor
->rcMonitor
.right
- width
;
2908 if( x
< monitor
->rcMonitor
.left
) x
= monitor
->rcMonitor
.left
;
2910 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2912 if( yanchor
&& y
>= height
+ yanchor
)
2913 y
-= height
+ yanchor
;
2915 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2916 y
= monitor
->rcMonitor
.bottom
- height
;
2918 if( y
< monitor
->rcMonitor
.top
) y
= monitor
->rcMonitor
.top
;
2920 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2924 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2929 top_popup
= menu
->hWnd
;
2930 top_popup_hmenu
= UserHMGetHandle(menu
);
2933 /* Display the window */
2934 UserRefObjectCo(pWnd
, &Ref
);
2935 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2937 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2939 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2940 UserDerefObjectCo(pWnd
);
2945 /***********************************************************************
2946 * MENU_EnsureMenuItemVisible
2948 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2950 USER_REFERENCE_ENTRY Ref
;
2951 if (lppop
->dwArrowsOn
)
2953 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2954 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2955 UINT nOldPos
= lppop
->iTop
;
2957 UINT arrow_bitmap_height
;
2958 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2960 IntGetClientRect(pWnd
, &rc
);
2962 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2964 rc
.top
+= arrow_bitmap_height
;
2965 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2967 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2968 UserRefObjectCo(pWnd
, &Ref
);
2969 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
2971 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
2972 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2973 MENU_DrawScrollArrows(lppop
, hdc
);
2974 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2976 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
2978 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
2979 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2980 MENU_DrawScrollArrows(lppop
, hdc
);
2981 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2983 UserDerefObjectCo(pWnd
);
2987 /***********************************************************************
2990 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
2991 BOOL sendMenuSelect
, PMENU topmenu
)
2996 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2998 if (!menu
|| !menu
->cItems
) return;
3000 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3004 if (menu
->iItem
== wIndex
) return;
3006 if (menu
->fFlags
& MNF_POPUP
)
3007 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
3009 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3012 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
3013 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
3014 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
3017 NtGdiSelectFont( hdc
, ghMenuFont
);
3019 /* Clear previous highlighted item */
3020 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3022 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
3023 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
3024 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
3028 /* Highlight new item (if any) */
3029 menu
->iItem
= wIndex
;
3030 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3032 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
3034 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
3035 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
3036 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
3037 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3041 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3042 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3043 ip
->fType
| ip
->fState
|
3044 (ip
->spSubMenu
? MF_POPUP
: 0) |
3045 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3047 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3050 else if (sendMenuSelect
)
3055 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3056 if (pos
!= NO_SELECTED_ITEM
)
3058 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3059 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3060 (ip
->spSubMenu
? MF_POPUP
: 0) |
3061 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3063 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3067 UserReleaseDC(pWnd
, hdc
, FALSE
);
3070 /***********************************************************************
3073 * Moves currently selected item according to the Offset parameter.
3074 * If there is no selection then it should select the last item if
3075 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3077 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3081 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3083 if ((!menu
) || (!menu
->rgItems
)) return;
3085 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3087 if ( menu
->cItems
== 1 )
3090 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3092 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3094 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3099 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3100 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3101 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3103 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3108 /***********************************************************************
3111 * Hide the sub-popup menus of this menu.
3113 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3114 BOOL SendMenuSelect
, UINT wFlags
)
3116 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3118 if ( Menu
&& top_popup
)
3122 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3124 Item
= &Menu
->rgItems
[Menu
->iItem
];
3125 if (!(Item
->spSubMenu
) ||
3126 !(Item
->fState
& MF_MOUSESELECT
)) return;
3127 Item
->fState
&= ~MF_MOUSESELECT
;
3132 if (Item
->spSubMenu
)
3135 if (!VerifyMenu(Item
->spSubMenu
)) return;
3136 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3137 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3138 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3139 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3140 co_UserDestroyWindow(pWnd
);
3142 /* Native returns handle to destroyed window */
3143 if (!(wFlags
& TPM_NONOTIFY
))
3145 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3146 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3149 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3150 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3152 Item
->spSubMenu
->hWnd
= NULL
;
3158 /***********************************************************************
3161 * Display the sub-menu of the selected item of this menu.
3162 * Return the handle of the submenu, or menu if no submenu to display.
3164 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3171 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3173 if (!Menu
) return Menu
;
3175 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3177 Item
= &Menu
->rgItems
[Menu
->iItem
];
3178 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3181 /* message must be sent before using item,
3182 because nearly everything may be changed by the application ! */
3184 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3185 if (!(Flags
& TPM_NONOTIFY
))
3187 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3188 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3189 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3192 Item
= &Menu
->rgItems
[Menu
->iItem
];
3193 //Rect = ItemInfo.Rect;
3194 Rect
.left
= Item
->xItem
;
3195 Rect
.top
= Item
->yItem
;
3196 Rect
.right
= Item
->cxItem
; // Do this for now......
3197 Rect
.bottom
= Item
->cyItem
;
3199 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3201 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3202 if (!(Item
->fState
& MF_HILITE
))
3204 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3205 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3207 NtGdiSelectFont(Dc
, ghMenuFont
);
3209 Item
->fState
|= MF_HILITE
;
3210 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3211 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3213 UserReleaseDC(pWnd
, Dc
, FALSE
);
3216 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3218 Item
->xItem
= Rect
.left
;
3219 Item
->yItem
= Rect
.top
;
3220 Item
->cxItem
= Rect
.right
; // Do this for now......
3221 Item
->cyItem
= Rect
.bottom
;
3223 Item
->fState
|= MF_MOUSESELECT
;
3225 if (IS_SYSTEM_MENU(Menu
))
3227 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3229 NC_GetSysPopupPos(pWnd
, &Rect
);
3230 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3231 Rect
.top
= Rect
.bottom
;
3232 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3233 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3237 IntGetWindowRect(pWnd
, &Rect
);
3238 if (Menu
->fFlags
& MNF_POPUP
)
3241 rc
.left
= Item
->xItem
;
3242 rc
.top
= Item
->yItem
;
3243 rc
.right
= Item
->cxItem
; // Do this for now......
3244 rc
.bottom
= Item
->cyItem
;
3246 MENU_AdjustMenuItemRect(Menu
, &rc
);
3248 /* The first item in the popup menu has to be at the
3249 same y position as the focused menu item */
3250 if(Flags
& TPM_LAYOUTRTL
)
3251 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3253 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3254 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3255 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3256 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3257 - UserGetSystemMetrics(SM_CYBORDER
);
3261 if(Flags
& TPM_LAYOUTRTL
)
3262 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3264 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3265 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3266 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3267 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3271 /* use default alignment for submenus */
3272 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3274 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3276 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3277 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3280 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3282 return Item
->spSubMenu
;
3285 /***********************************************************************
3286 * MenuExecFocusedItem
3288 * Execute a menu item (for instance when user pressed Enter).
3289 * Return the wID of the executed item. Otherwise, -1 indicating
3290 * that no menu item was executed, -2 if a popup is shown;
3291 * Have to receive the flags for the TrackPopupMenu options to avoid
3292 * sending unwanted message.
3295 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3299 TRACE("%p menu=%p\n", pmt
, Menu
);
3301 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3306 Item
= &Menu
->rgItems
[Menu
->iItem
];
3308 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3310 if (!(Item
->spSubMenu
))
3312 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3314 /* If TPM_RETURNCMD is set you return the id, but
3315 do not send a message to the owner */
3316 if (!(Flags
& TPM_RETURNCMD
))
3318 if (Menu
->fFlags
& MNF_SYSMENU
)
3320 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3321 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3325 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3327 if (dwStyle
& MNS_NOTIFYBYPOS
)
3328 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3330 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3338 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3345 /***********************************************************************
3346 * MenuSwitchTracking
3348 * Helper function for menu navigation routines.
3350 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3352 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3354 if ( pmt
->TopMenu
!= PtMenu
&&
3355 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3357 /* both are top level menus (system and menu-bar) */
3358 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3359 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3360 pmt
->TopMenu
= PtMenu
;
3364 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3367 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3370 /***********************************************************************
3373 * Return TRUE if we can go on with menu tracking.
3375 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3377 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3383 if (IS_SYSTEM_MENU(PtMenu
))
3385 item
= PtMenu
->rgItems
;
3389 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3394 if (PtMenu
->iItem
!= id
)
3395 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3397 /* If the popup menu is not already "popped" */
3398 if (!(item
->fState
& MF_MOUSESELECT
))
3400 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3405 /* Else the click was on the menu bar, finish the tracking */
3410 /***********************************************************************
3413 * Return the value of MenuExecFocusedItem if
3414 * the selected item was not a popup. Else open the popup.
3415 * A -1 return value indicates that we go on with menu tracking.
3418 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3420 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3427 if ( IS_SYSTEM_MENU(PtMenu
) )
3429 item
= PtMenu
->rgItems
;
3433 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3436 if (item
&& ( PtMenu
->iItem
== Id
))
3438 if (!(item
->spSubMenu
))
3440 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3441 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3442 return ExecutedMenuId
;
3445 /* If we are dealing with the menu bar */
3446 /* and this is a click on an already "popped" item: */
3447 /* Stop the menu tracking and close the opened submenus */
3448 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3453 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3455 PtMenu
->TimeToHide
= TRUE
;
3461 /***********************************************************************
3464 * Walks menu chain trying to find a menu pt maps to.
3466 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3471 if (!menu
) return NULL
;
3473 /* try subpopup first (if any) */
3474 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3476 pItem
= menu
->rgItems
;
3477 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3478 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3480 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3484 /* check the current window (avoiding WM_HITTEST) */
3487 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3488 INT ht
= GetNCHitEx(pWnd
, pt
);
3489 if ( menu
->fFlags
& MNF_POPUP
)
3491 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3493 else if (ht
== HTSYSMENU
)
3494 ret
= get_win_sys_menu(menu
->hWnd
);
3495 else if (ht
== HTMENU
)
3496 ret
= IntGetMenu( menu
->hWnd
);
3501 /***********************************************************************
3504 * Return TRUE if we can go on with menu tracking.
3506 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3508 UINT Index
= NO_SELECTED_ITEM
;
3512 if (IS_SYSTEM_MENU(PtMenu
))
3515 //// ReactOS only HACK: CORE-2338
3516 // Windows tracks mouse moves to the system menu but does not open it.
3517 // Only keyboard tracking can do that.
3519 TRACE("SystemMenu\n");
3520 return TRUE
; // Stay inside the Loop!
3523 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3526 if (Index
== NO_SELECTED_ITEM
)
3528 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3530 else if (PtMenu
->iItem
!= Index
)
3532 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3533 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3538 /***********************************************************************
3541 * Return the handle of the selected sub-popup menu (if any).
3543 static PMENU
MENU_GetSubPopup( PMENU menu
)
3547 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3549 item
= &menu
->rgItems
[menu
->iItem
];
3550 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3552 return item
->spSubMenu
;
3557 /***********************************************************************
3560 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3562 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3566 /* When skipping left, we need to do something special after the
3568 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3572 /* When skipping right, for the non-system menu, we need to
3573 handle the last non-special menu item (ie skip any window
3574 icons such as MDI maximize, restore or close) */
3575 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3577 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3578 while (i
< pmt
->TopMenu
->cItems
) {
3579 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3580 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3584 if (i
== pmt
->TopMenu
->cItems
) {
3588 /* When skipping right, we need to cater for the system menu */
3589 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3591 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3598 MDINEXTMENU NextMenu
;
3605 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3606 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3607 NextMenu
.hmenuNext
= NULL
;
3608 NextMenu
.hwndNext
= NULL
;
3609 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3611 TRACE("%p [%p] -> %p [%p]\n",
3612 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3614 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3616 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3617 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3619 /* switch to the menu bar */
3621 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3625 Id
= MenuTmp
->cItems
- 1;
3627 /* Skip backwards over any system predefined icons,
3628 eg. MDI close, restore etc icons */
3630 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3631 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3634 hNewMenu
= UserHMGetHandle(MenuTmp
);
3636 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3638 /* switch to the system menu */
3639 MenuTmp
= get_win_sys_menu(hNewWnd
);
3640 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3645 else /* application returned a new menu to switch to */
3647 hNewMenu
= NextMenu
.hmenuNext
;
3648 hNewWnd
= NextMenu
.hwndNext
;
3650 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3652 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3654 /* get the real system menu */
3655 MenuTmp
= get_win_sys_menu(hNewWnd
);
3656 hNewMenu
= UserHMGetHandle(MenuTmp
);
3658 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3660 /* FIXME: Not sure what to do here;
3661 * perhaps try to track NewMenu as a popup? */
3663 WARN(" -- got confused.\n");
3670 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3672 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3674 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3675 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3678 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3680 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3681 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3682 ///// Use thread pms!!!!
3683 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3684 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3685 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3686 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3689 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3690 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3697 /***********************************************************************
3700 * The idea is not to show the popup if the next input message is
3701 * going to hide it anyway.
3703 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3707 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3709 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3710 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3715 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3716 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3718 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3719 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3720 if( msg
.message
== WM_KEYDOWN
&&
3721 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3723 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3729 /* failures go through this */
3730 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3734 /***********************************************************************
3737 * Handle a VK_ESCAPE key event in a menu.
3739 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3741 BOOL EndMenu
= TRUE
;
3743 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3745 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3747 PMENU MenuPrev
, MenuTmp
;
3749 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3751 /* close topmost popup */
3752 while (MenuTmp
!= pmt
->CurrentMenu
)
3755 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3758 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3759 pmt
->CurrentMenu
= MenuPrev
;
3767 /***********************************************************************
3770 * Handle a VK_LEFT key event in a menu.
3772 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
, UINT msg
)
3774 PMENU MenuTmp
, MenuPrev
;
3777 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3779 /* Try to move 1 column left (if possible) */
3780 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3782 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3786 /* close topmost popup */
3787 while (MenuTmp
!= pmt
->CurrentMenu
)
3790 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3793 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3794 pmt
->CurrentMenu
= MenuPrev
;
3796 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3798 /* move menu bar selection if no more popups are left */
3800 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3801 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3803 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3805 /* A sublevel menu was displayed - display the next one
3806 * unless there is another displacement coming up */
3808 if (!MENU_SuspendPopup(pmt
, msg
))
3809 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3815 /***********************************************************************
3818 * Handle a VK_RIGHT key event in a menu.
3820 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
, UINT msg
)
3825 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3826 pmt
->CurrentMenu
, pmt
->TopMenu
);
3828 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3830 /* If already displaying a popup, try to display sub-popup */
3832 menutmp
= pmt
->CurrentMenu
;
3833 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3835 /* if subpopup was displayed then we are done */
3836 if (menutmp
!= pmt
->CurrentMenu
) return;
3839 /* Check to see if there's another column */
3840 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3842 TRACE("Going to %d.\n", NextCol
);
3843 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3847 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3849 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3851 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3852 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3859 /* try to move to the next item */
3860 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3861 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3863 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3865 if ( !MENU_SuspendPopup(pmt
, msg
) )
3866 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3871 /***********************************************************************
3874 * Menu tracking code.
3876 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3877 PWND pwnd
, const RECT
*lprect
)
3881 INT executedMenuId
= -1;
3885 BOOL enterIdleSent
= FALSE
;
3886 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3888 if (pti
!= pwnd
->head
.pti
)
3890 ERR("Not the same PTI!!!!\n");
3894 mt
.CurrentMenu
= pmenu
;
3900 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3901 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3902 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3904 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3906 if (wFlags
& TPM_BUTTONDOWN
)
3908 /* Get the result in order to start the tracking or not */
3909 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3910 fInsideMenuLoop
= fRemove
;
3913 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3915 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3917 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3918 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3919 co_UserSetCapture(NULL
); /* release the capture */
3923 capture_win
= IntGetCapture();
3925 while (fInsideMenuLoop
)
3927 BOOL ErrorExit
= FALSE
;
3928 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3931 /* we have to keep the message in the queue until it's
3932 * clear that menu loop is not over yet. */
3936 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3938 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3939 /* remove the message from the queue */
3940 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3944 /* ReactOS Checks */
3945 if (!VerifyWnd(mt
.OwnerWnd
) ||
3946 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3947 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3948 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3950 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3956 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3957 enterIdleSent
= TRUE
;
3958 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3960 co_IntWaitMessage(NULL
, 0, 0);
3964 if (ErrorExit
) break; // Gracefully dropout.
3966 /* check if EndMenu() tried to cancel us, by posting this message */
3967 if (msg
.message
== WM_CANCELMODE
)
3969 /* we are now out of the loop */
3970 fInsideMenuLoop
= FALSE
;
3972 /* remove the message from the queue */
3973 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3975 /* break out of internal loop, ala ESCAPE */
3981 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3982 enterIdleSent
=FALSE
;
3985 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3988 * Use the mouse coordinates in lParam instead of those in the MSG
3989 * struct to properly handle synthetic messages. They are already
3990 * in screen coordinates.
3992 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3993 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3995 /* Find a menu for this mouse event */
3996 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
4000 /* no WM_NC... messages in captured state */
4002 case WM_RBUTTONDBLCLK
:
4003 case WM_RBUTTONDOWN
:
4004 if (!(wFlags
& TPM_RIGHTBUTTON
))
4006 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
4010 case WM_LBUTTONDBLCLK
:
4011 case WM_LBUTTONDOWN
:
4012 /* If the message belongs to the menu, removes it from the queue */
4013 /* Else, end menu tracking */
4014 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
4015 fInsideMenuLoop
= fRemove
;
4016 if ( msg
.message
== WM_LBUTTONDBLCLK
||
4017 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
4021 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
4024 /* Check if a menu was selected by the mouse */
4027 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
4029 /* End the loop if executedMenuId is an item ID */
4030 /* or if the job was done (executedMenuId = 0). */
4031 fRemove
= (executedMenuId
!= -1);
4032 fInsideMenuLoop
= !fRemove
;
4034 /* No menu was selected by the mouse */
4035 /* if the function was called by TrackPopupMenu, continue
4036 with the menu tracking. If not, stop it */
4038 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4043 /* the selected menu item must be changed every time */
4044 /* the mouse moves. */
4047 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4049 } /* switch(msg.message) - mouse */
4051 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4053 fRemove
= TRUE
; /* Keyboard messages are always removed */
4062 fInsideMenuLoop
= FALSE
;
4067 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4068 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4072 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4073 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4074 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4075 else /* otherwise try to move selection */
4076 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4080 MENU_KeyLeft( &mt
, wFlags
, msg
.message
);
4084 MENU_KeyRight( &mt
, wFlags
, msg
.message
);
4088 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4094 hi
.cbSize
= sizeof(HELPINFO
);
4095 hi
.iContextType
= HELPINFO_MENUITEM
;
4096 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4099 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4100 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4101 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4102 hi
.MousePos
= msg
.pt
;
4103 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4108 IntTranslateKbdMessage(&msg
, 0);
4111 break; /* WM_KEYDOWN */
4119 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4121 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4122 fEndMenu
= (executedMenuId
!= -2);
4123 fInsideMenuLoop
= !fEndMenu
;
4127 /* Hack to avoid control chars. */
4128 /* We will find a better way real soon... */
4129 if (msg
.wParam
< 32) break;
4131 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4133 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4134 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4137 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4138 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4139 fEndMenu
= (executedMenuId
!= -2);
4140 fInsideMenuLoop
= !fEndMenu
;
4144 } /* switch(msg.message) - kbd */
4148 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4149 IntDispatchMessage( &msg
);
4153 if (fInsideMenuLoop
) fRemove
= TRUE
;
4155 /* finally remove message from the queue */
4157 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4158 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4159 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4162 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4163 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4164 co_UserSetCapture(NULL
); /* release the capture */
4166 /* If dropdown is still painted and the close box is clicked on
4167 then the menu will be destroyed as part of the DispatchMessage above.
4168 This will then invalidate the menu handle in mt.hTopMenu. We should
4169 check for this first. */
4170 if ( VerifyMenu( mt
.TopMenu
) )
4172 if (VerifyWnd(mt
.OwnerWnd
))
4174 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4176 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4178 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4181 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4183 co_UserDestroyWindow(pwndTM
);
4185 mt
.TopMenu
->hWnd
= NULL
;
4187 if (!(wFlags
& TPM_NONOTIFY
))
4189 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4190 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4193 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4194 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4197 /* Reset the variable for hiding menu */
4198 mt
.TopMenu
->TimeToHide
= FALSE
;
4201 EngSetLastError( ERROR_SUCCESS
);
4202 /* The return value is only used by TrackPopupMenu */
4203 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4204 if (executedMenuId
== -1) executedMenuId
= 0;
4205 return executedMenuId
;
4208 /***********************************************************************
4211 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4214 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4216 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4218 co_UserHideCaret(0);
4220 /* This makes the menus of applications built with Delphi work.
4221 * It also enables menus to be displayed in more than one window,
4222 * but there are some bugs left that need to be fixed in this case.
4226 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4230 top_popup
= Menu
->hWnd
;
4231 top_popup_hmenu
= UserHMGetHandle(Menu
);
4234 fInsideMenuLoop
= TRUE
;
4237 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4238 if (!(wFlags
& TPM_NONOTIFY
))
4240 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4244 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4246 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4247 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4248 co_UserSetCapture(capture_win
); // 2
4249 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4251 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4253 if (!(wFlags
& TPM_NONOTIFY
))
4255 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4256 /* If an app changed/recreated menu bar entries in WM_INITMENU
4257 * menu sizes will be recalculated once the menu created/shown.
4261 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4263 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4268 /***********************************************************************
4271 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4273 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4275 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4277 if (!(wFlags
& TPM_NONOTIFY
))
4278 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4280 co_UserShowCaret(0);
4283 top_popup_hmenu
= NULL
;
4288 /***********************************************************************
4289 * MenuTrackMouseMenuBar
4291 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4293 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4295 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) ); // See 74276 and CORE-12801
4296 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4298 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4300 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4301 if (VerifyMenu(pMenu
))
4303 /* map point to parent client coordinates */
4304 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4305 if (Parent
!= UserGetDesktopWindow())
4307 IntScreenToClient(Parent
, &pt
);
4310 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4311 /* fetch the window menu again, it may have changed */
4312 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4313 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4314 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4318 /***********************************************************************
4319 * MenuTrackKbdMenuBar
4321 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4323 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4325 UINT uItem
= NO_SELECTED_ITEM
;
4327 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4329 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4331 /* find window that has a menu */
4333 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4334 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4336 /* check if we have to track a system menu */
4338 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4339 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4341 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4342 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4344 wParam
|= HTSYSMENU
; /* prevent item lookup */
4347 if (!VerifyMenu( TrackMenu
)) return;
4349 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4351 /* fetch the window menu again, it may have changed */
4352 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4354 if( wChar
&& wChar
!= ' ' )
4356 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4357 if ( uItem
>= (UINT
)(-2) )
4359 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4360 /* schedule end of menu tracking */
4361 wFlags
|= TF_ENDMENU
;
4366 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4368 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4370 if( uItem
== NO_SELECTED_ITEM
)
4371 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4373 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4377 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4378 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4381 /**********************************************************************
4382 * TrackPopupMenuEx (USER32.@)
4384 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4385 PWND pWnd
, LPTPMPARAMS lpTpm
)
4388 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4390 if (pti
!= pWnd
->head
.pti
)
4392 ERR("Must be the same pti!\n");
4396 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4397 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4398 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4400 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4402 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4406 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4408 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4410 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4411 if (!(wFlags
& TPM_NONOTIFY
))
4413 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4416 if (menu
->fFlags
& MNF_SYSMENU
)
4417 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4419 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4420 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4421 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4424 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4425 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4426 co_UserSetCapture(NULL
); /* release the capture */
4429 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4433 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4434 if (pwndM
) // wine hack around this with their destroy function.
4436 if (!(pWnd
->state
& WNDS_DESTROYED
))
4437 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4441 if (!(wFlags
& TPM_NONOTIFY
))
4443 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4444 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4462 PPOPUPMENU pPopupMenu
;
4466 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4472 if (Message
!= WM_NCCREATE
)
4474 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4477 Wnd
->fnid
= FNID_MENU
;
4478 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4479 if (pPopupMenu
== NULL
)
4483 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4484 pPopupMenu
->spwndPopupMenu
= Wnd
;
4485 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4486 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4492 if (Wnd
->fnid
!= FNID_MENU
)
4494 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4497 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4505 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4506 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4510 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4511 *lResult
= MA_NOACTIVATE
;
4517 IntBeginPaint(Wnd
, &ps
);
4518 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4519 IntEndPaint(Wnd
, &ps
);
4523 case WM_PRINTCLIENT
:
4525 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4534 /* zero out global pointer in case resident popup window was destroyed. */
4537 if (UserHMGetHandle(Wnd
) == top_popup
)
4540 top_popup_hmenu
= NULL
;
4545 ERR("No Window Pop Up!\n");
4551 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4552 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4553 Wnd
->fnid
= FNID_DESTROY
;
4557 case MM_SETMENUHANDLE
: // wine'isms
4560 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4563 ERR("Bad Menu Handle\n");
4566 pPopupMenu
->spmenu
= pmenu
;
4570 case MM_GETMENUHANDLE
: // wine'isms
4572 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4576 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4578 ERR("Someone is passing unknown menu messages %d\n",Message
);
4580 TRACE("PMWP to IDWP %d\n",Message
);
4581 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4589 IntHiliteMenuItem(PWND WindowObject
,
4595 UINT uItem
= uItemHilite
;
4597 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4599 if (uHilite
& MF_HILITE
)
4601 MenuItem
->fState
|= MF_HILITE
;
4605 MenuItem
->fState
&= ~MF_HILITE
;
4607 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4608 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4609 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4611 return TRUE
; // Always returns true!!!!
4615 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4619 DWORD dwExStyle
= 0;
4620 BOOLEAN retValue
= TRUE
;
4622 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4624 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4626 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4628 dwStyle
= pWindowObject
->style
;
4629 dwExStyle
= pWindowObject
->ExStyle
;
4631 bti
->rcTitleBar
.top
= 0;
4632 bti
->rcTitleBar
.left
= 0;
4633 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4634 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4636 /* Is it iconiced ? */
4637 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4639 /* Remove frame from rectangle */
4640 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4642 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4643 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4645 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4647 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4648 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4650 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4652 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4653 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4656 /* We have additional border information if the window
4657 * is a child (but not an MDI child) */
4658 if ( (dwStyle
& WS_CHILD
) &&
4659 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4661 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4663 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4664 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4667 if (dwExStyle
& WS_EX_STATICEDGE
)
4669 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4670 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4675 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4676 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4677 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4679 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4680 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4682 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4683 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4687 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4688 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4689 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4692 if (dwStyle
& WS_CAPTION
)
4694 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4695 if (dwStyle
& WS_SYSMENU
)
4697 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4699 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4700 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4704 if (!(dwStyle
& WS_MINIMIZEBOX
))
4706 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4708 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4710 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4714 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4716 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4718 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4720 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4725 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4726 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4727 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4728 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4733 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4738 EngSetLastError(ERROR_INVALID_PARAMETER
);
4750 LPCMENUITEMINFOW UnsafeItemInfo
,
4751 PUNICODE_STRING lpstr
)
4754 ROSMENUITEMINFO ItemInfo
;
4756 /* Try to copy the whole MENUITEMINFOW structure */
4757 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4758 if (NT_SUCCESS(Status
))
4760 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4761 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4763 EngSetLastError(ERROR_INVALID_PARAMETER
);
4766 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4769 /* Try to copy without last field (not present in older versions) */
4770 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4771 if (NT_SUCCESS(Status
))
4773 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4775 EngSetLastError(ERROR_INVALID_PARAMETER
);
4778 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4779 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4782 SetLastNtError(Status
);
4786 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4791 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4796 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4798 if (pItem
->spSubMenu
)
4800 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4803 return (pItem
->fType
| pItem
->fState
);
4806 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4811 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4816 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4818 if (pItem
->spSubMenu
)
4820 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4826 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4828 PMENU menu
, pSubTarget
;
4830 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4831 return NO_SELECTED_ITEM
;
4833 pSubTarget
= UserGetMenuObject(hSubTarget
);
4835 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4837 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4843 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4845 PWINSTATION_OBJECT WinStaObject
;
4849 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4851 if (gpepCSRSS
!= CurrentProcess
)
4854 * gpepCSRSS does not have a Win32WindowStation
4857 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4863 if (!NT_SUCCESS(Status
))
4865 ERR("Validation of window station handle (%p) failed\n",
4866 CurrentProcess
->Win32WindowStation
);
4867 SetLastNtError(Status
);
4870 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4871 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4873 ERR("Desktop Window Station does not match Process one!\n");
4875 ObDereferenceObject(WinStaObject
);
4879 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4882 if (Menu
) UserDereferenceObject(Menu
);
4883 return (HMENU
)Handle
;
4891 PROSMENUITEMINFO ItemInfo
,
4893 PUNICODE_STRING lpstr
)
4898 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4900 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4905 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4909 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4919 PROSMENUITEMINFO UnsafeItemInfo
,
4921 PUNICODE_STRING lpstr
)
4924 ROSMENUITEMINFO ItemInfo
;
4929 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4930 if (! NT_SUCCESS(Status
))
4932 SetLastNtError(Status
);
4935 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4936 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4937 Size
!= sizeof(ROSMENUITEMINFO
) )
4939 EngSetLastError(ERROR_INVALID_PARAMETER
);
4942 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4943 if (! NT_SUCCESS(Status
))
4945 SetLastNtError(Status
);
4948 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4950 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4951 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4953 EngSetLastError(ERROR_INVALID_PARAMETER
);
4957 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4959 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4960 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4963 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4969 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4973 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4976 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4977 if (! NT_SUCCESS(Status
))
4979 SetLastNtError(Status
);
4991 PROSMENUINFO UnsafeMenuInfo
,
4997 ROSMENUINFO MenuInfo
;
4999 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
5000 if (! NT_SUCCESS(Status
))
5002 SetLastNtError(Status
);
5005 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
5007 EngSetLastError(ERROR_INVALID_PARAMETER
);
5010 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
5011 if (! NT_SUCCESS(Status
))
5013 SetLastNtError(Status
);
5020 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
5025 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
5028 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
5029 if (! NT_SUCCESS(Status
))
5031 SetLastNtError(Status
);
5051 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5053 Rect
->left
= MenuItem
->xItem
;
5054 Rect
->top
= MenuItem
->yItem
;
5055 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5056 Rect
->bottom
= MenuItem
->cyItem
;
5060 ERR("Failed Item Lookup! %u\n", uItem
);
5066 HWND hWnd
= Menu
->hWnd
;
5067 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5070 if (Menu
->fFlags
& MNF_POPUP
)
5072 XMove
= pWnd
->rcClient
.left
;
5073 YMove
= pWnd
->rcClient
.top
;
5077 XMove
= pWnd
->rcWindow
.left
;
5078 YMove
= pWnd
->rcWindow
.top
;
5081 Rect
->left
+= XMove
;
5083 Rect
->right
+= XMove
;
5084 Rect
->bottom
+= YMove
;
5089 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5091 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5092 HMENU hSysMenu
, hNewMenu
= NULL
;
5093 ROSMENUITEMINFO ItemInfoSet
= {0};
5094 ROSMENUITEMINFO ItemInfo
= {0};
5095 UNICODE_STRING MenuName
;
5097 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5098 if (NULL
== hSysMenu
)
5102 SysMenu
= UserGetMenuObject(hSysMenu
);
5103 if (NULL
== SysMenu
)
5105 UserDestroyMenu(hSysMenu
);
5109 SysMenu
->fFlags
|= MNF_SYSMENU
;
5110 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5114 //hNewMenu = co_IntLoadSysMenuTemplate();
5115 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5117 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5118 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5122 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5123 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5124 //ERR("%wZ\n",&MenuName);
5129 IntDestroyMenuObject(SysMenu
, FALSE
);
5132 Menu
= UserGetMenuObject(hNewMenu
);
5135 IntDestroyMenuObject(SysMenu
, FALSE
);
5139 // Do the rest in here.
5141 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5143 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5144 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5145 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5146 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5147 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5148 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5149 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5150 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5151 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5152 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5154 NewMenu
= IntCloneMenu(Menu
);
5155 if (NewMenu
== NULL
)
5157 IntDestroyMenuObject(Menu
, FALSE
);
5158 IntDestroyMenuObject(SysMenu
, FALSE
);
5162 IntReleaseMenuObject(NewMenu
);
5163 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5165 IntDestroyMenuObject(Menu
, FALSE
);
5173 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5175 if (Window
->pcls
->style
& CS_NOCLOSE
)
5176 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5178 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5179 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5180 ItemInfo
.fType
= MF_POPUP
;
5181 ItemInfo
.fState
= MFS_ENABLED
;
5182 ItemInfo
.dwTypeData
= NULL
;
5184 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5185 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5189 ERR("failed to load system menu!\n");
5194 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5200 if (Window
->SystemMenu
)
5202 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5203 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5205 IntDestroyMenuObject(Menu
, TRUE
);
5206 Window
->SystemMenu
= NULL
;
5212 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5213 if ((!Menu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5215 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5216 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5220 if (Window
->SystemMenu
)
5222 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5223 /* Store the dummy sysmenu handle to facilitate the refresh */
5224 /* of the close button if the SC_CLOSE item change */
5225 Menu
= UserGetMenuObject(hMenu
);
5228 Menu
->spwndNotify
= Window
;
5229 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5237 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5241 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5243 if (Window
->SystemMenu
)
5245 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5248 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5249 IntDestroyMenuObject(OldMenu
, TRUE
);
5253 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5255 { // Use spmenuSys too!
5256 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5259 Window
->SystemMenu
= NULL
;
5261 if (Menu
&& Window
!= Menu
->spwndNotify
)
5263 Menu
->spwndNotify
= Window
;
5275 PMENU OldMenu
, NewMenu
= NULL
;
5277 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5279 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5280 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5284 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5292 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5293 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5302 NewMenu
= IntGetMenuObject(Menu
);
5303 if (NULL
== NewMenu
)
5305 if (NULL
!= OldMenu
)
5307 IntReleaseMenuObject(OldMenu
);
5309 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5312 if (NULL
!= NewMenu
->hWnd
)
5314 /* Can't use the same menu for two windows */
5315 if (NULL
!= OldMenu
)
5317 IntReleaseMenuObject(OldMenu
);
5319 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5325 Wnd
->IDMenu
= (UINT_PTR
) Menu
;
5326 if (NULL
!= NewMenu
)
5328 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5329 IntReleaseMenuObject(NewMenu
);
5331 if (NULL
!= OldMenu
)
5333 OldMenu
->hWnd
= NULL
;
5334 IntReleaseMenuObject(OldMenu
);
5341 /* FUNCTIONS *****************************************************************/
5346 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5361 UserEnterExclusive();
5363 if(!(Window
= UserGetWindowObject(hwnd
)))
5365 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5370 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5377 Rect
.left
= leftBorder
;
5378 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5382 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5384 UserReleaseDC( 0, hdc
, FALSE
);
5395 NtUserCheckMenuItem(
5401 DECLARE_RETURN(DWORD
);
5403 TRACE("Enter NtUserCheckMenuItem\n");
5404 UserEnterExclusive();
5406 if(!(Menu
= UserGetMenuObject(hMenu
)))
5411 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5414 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5429 DECLARE_RETURN(BOOL
);
5431 TRACE("Enter NtUserDeleteMenu\n");
5432 UserEnterExclusive();
5434 if(!(Menu
= UserGetMenuObject(hMenu
)))
5439 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5442 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5448 * NtUserGetSystemMenu
5450 * The NtUserGetSystemMenu function allows the application to access the
5451 * window menu (also known as the system menu or the control menu) for
5452 * copying and modifying.
5456 * Handle to the window that will own a copy of the window menu.
5458 * Specifies the action to be taken. If this parameter is FALSE,
5459 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5460 * currently in use. The copy is initially identical to the window menu
5461 * but it can be modified.
5462 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5463 * to the default state. The previous window menu, if any, is destroyed.
5466 * If the bRevert parameter is FALSE, the return value is a handle to a
5467 * copy of the window menu. If the bRevert parameter is TRUE, the return
5475 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5479 DECLARE_RETURN(HMENU
);
5481 TRACE("Enter NtUserGetSystemMenu\n");
5484 if (!(Window
= UserGetWindowObject(hWnd
)))
5489 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5494 RETURN(Menu
->head
.h
);
5497 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5503 * NtUserSetSystemMenu
5510 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5512 BOOL Result
= FALSE
;
5515 DECLARE_RETURN(BOOL
);
5517 TRACE("Enter NtUserSetSystemMenu\n");
5518 UserEnterExclusive();
5520 if (!(Window
= UserGetWindowObject(hWnd
)))
5528 * Assign new menu handle and Up the Lock Count.
5530 if (!(Menu
= IntGetMenuObject(hMenu
)))
5535 Result
= IntSetSystemMenu(Window
, Menu
);
5538 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5543 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5552 NtUserGetTitleBarInfo(
5557 TITLEBARINFO bartitleinfo
;
5558 DECLARE_RETURN(BOOLEAN
);
5559 BOOLEAN retValue
= TRUE
;
5561 TRACE("Enter NtUserGetTitleBarInfo\n");
5562 UserEnterExclusive();
5564 /* Vaildate the windows handle */
5565 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5567 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5573 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5574 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5575 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5579 /* Fail copy the data */
5580 EngSetLastError(ERROR_INVALID_PARAMETER
);
5585 /* Get the tile bar info */
5588 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5593 /* Copy our buffer to user mode buffer bti */
5594 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5595 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5597 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5599 /* Fail copy the data */
5600 EngSetLastError(ERROR_INVALID_PARAMETER
);
5610 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5618 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5621 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5623 if(!(Menu
= UserGetMenuObject(hMenu
)))
5628 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5630 EngSetLastError(ERROR_ACCESS_DENIED
);
5633 return IntDestroyMenuObject(Menu
, FALSE
);
5644 DECLARE_RETURN(BOOL
);
5646 TRACE("Enter NtUserDestroyMenu\n");
5647 UserEnterExclusive();
5649 if(!(Menu
= UserGetMenuObject(hMenu
)))
5653 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5655 EngSetLastError(ERROR_ACCESS_DENIED
);
5658 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5661 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5670 NtUserEnableMenuItem(
5676 DECLARE_RETURN(UINT
);
5678 TRACE("Enter NtUserEnableMenuItem\n");
5679 UserEnterExclusive();
5681 if(!(Menu
= UserGetMenuObject(hMenu
)))
5686 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5689 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5701 TRACE("Enter NtUserEndMenu\n");
5702 UserEnterExclusive();
5703 /* if ( gptiCurrent->pMenuState &&
5704 gptiCurrent->pMenuState->pGlobalPopupMenu )
5706 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5709 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5712 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5714 if (fInsideMenuLoop
&& top_popup
)
5716 fInsideMenuLoop
= FALSE
;
5717 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5720 TRACE("Leave NtUserEndMenu\n");
5728 NtUserGetMenuBarInfo(
5738 PPOPUPMENU pPopupMenu
;
5739 USER_REFERENCE_ENTRY Ref
;
5740 NTSTATUS Status
= STATUS_SUCCESS
;
5742 DECLARE_RETURN(BOOL
);
5744 TRACE("Enter NtUserGetMenuBarInfo\n");
5747 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5749 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5753 UserRefObjectCo(pWnd
, &Ref
);
5755 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5757 kmbi
.hwndMenu
= NULL
;
5758 kmbi
.fBarFocused
= FALSE
;
5759 kmbi
.fFocused
= FALSE
;
5764 if (!pWnd
->pcls
->fnid
)
5766 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5768 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5769 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5772 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5773 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5774 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5775 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5777 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5779 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5784 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5785 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5786 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5789 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5790 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5791 hMenu
= UserHMGetHandle(Menu
);
5802 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5803 kmbi
.cbSize
= pmbi
->cbSize
;
5805 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5811 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5813 EngSetLastError(ERROR_INVALID_PARAMETER
);
5817 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5821 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5826 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5827 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5828 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5829 TRACE("idItem a 0 %d\n",Ret
);
5833 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5834 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5838 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5839 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5842 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5843 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5845 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5850 kmbi
.fFocused
= kmbi
.fBarFocused
;
5855 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5856 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5858 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5860 Status
= _SEH2_GetExceptionCode();
5864 if (!NT_SUCCESS(Status
))
5866 SetLastNtError(Status
);
5873 if (pWnd
) UserDerefObjectCo(pWnd
);
5874 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5887 PMENU Menu
, SubMenu
;
5890 DECLARE_RETURN(UINT
);
5892 TRACE("Enter NtUserGetMenuIndex\n");
5895 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5896 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5899 MenuItem
= Menu
->rgItems
;
5900 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5902 if (MenuItem
->spSubMenu
== SubMenu
)
5903 RETURN(MenuItem
->wID
);
5908 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5917 NtUserGetMenuItemRect(
5928 NTSTATUS Status
= STATUS_SUCCESS
;
5929 DECLARE_RETURN(BOOL
);
5931 TRACE("Enter NtUserGetMenuItemRect\n");
5934 if (!(Menu
= UserGetMenuObject(hMenu
)))
5939 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5941 Rect
.left
= MenuItem
->xItem
;
5942 Rect
.top
= MenuItem
->yItem
;
5943 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5944 Rect
.bottom
= MenuItem
->cyItem
;
5954 if (lprcItem
== NULL
) RETURN( FALSE
);
5956 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5958 if (Menu
->fFlags
& MNF_POPUP
)
5960 XMove
= ReferenceWnd
->rcClient
.left
;
5961 YMove
= ReferenceWnd
->rcClient
.top
;
5965 XMove
= ReferenceWnd
->rcWindow
.left
;
5966 YMove
= ReferenceWnd
->rcWindow
.top
;
5971 Rect
.right
+= XMove
;
5972 Rect
.bottom
+= YMove
;
5976 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5978 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5980 Status
= _SEH2_GetExceptionCode();
5984 if (!NT_SUCCESS(Status
))
5986 SetLastNtError(Status
);
5992 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
6001 NtUserHiliteMenuItem(
6009 DECLARE_RETURN(BOOLEAN
);
6011 TRACE("Enter NtUserHiliteMenuItem\n");
6012 UserEnterExclusive();
6014 if(!(Window
= UserGetWindowObject(hWnd
)))
6016 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6020 if(!(Menu
= UserGetMenuObject(hMenu
)))
6022 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6026 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
6029 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
6039 NtUserDrawMenuBarTemp(
6049 NTSTATUS Status
= STATUS_SUCCESS
;
6050 DECLARE_RETURN(DWORD
);
6052 ERR("Enter NtUserDrawMenuBarTemp\n");
6053 UserEnterExclusive();
6055 if(!(Window
= UserGetWindowObject(hWnd
)))
6057 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6061 if(!(Menu
= UserGetMenuObject(hMenu
)))
6063 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6069 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6070 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6072 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6074 Status
= _SEH2_GetExceptionCode();
6078 if (Status
!= STATUS_SUCCESS
)
6080 SetLastNtError(Status
);
6084 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6087 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6096 NtUserMenuItemFromPoint(
6106 DECLARE_RETURN(int);
6108 TRACE("Enter NtUserMenuItemFromPoint\n");
6109 UserEnterExclusive();
6111 if (!(Menu
= UserGetMenuObject(hMenu
)))
6116 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6121 X
-= Window
->rcWindow
.left
;
6122 Y
-= Window
->rcWindow
.top
;
6125 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6129 Rect
.left
= mi
->xItem
;
6130 Rect
.top
= mi
->yItem
;
6131 Rect
.right
= mi
->cxItem
;
6132 Rect
.bottom
= mi
->cyItem
;
6134 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6136 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6142 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6145 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6165 UserEnterExclusive();
6167 if(!(Window
= UserGetWindowObject(hWnd
)))
6169 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6174 Rect
.left
= leftBorder
;
6175 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6179 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6196 DECLARE_RETURN(BOOL
);
6198 TRACE("Enter NtUserRemoveMenu\n");
6199 UserEnterExclusive();
6201 if(!(Menu
= UserGetMenuObject(hMenu
)))
6206 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6209 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6226 DECLARE_RETURN(BOOL
);
6228 TRACE("Enter NtUserSetMenu\n");
6229 UserEnterExclusive();
6231 if (!(Window
= UserGetWindowObject(hWnd
)))
6236 if (!IntSetMenu(Window
, Menu
, &Changed
))
6241 // Not minimized and please repaint!!!
6242 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6244 USER_REFERENCE_ENTRY Ref
;
6245 UserRefObjectCo(Window
, &Ref
);
6246 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6247 UserDerefObjectCo(Window
);
6253 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6262 NtUserSetMenuContextHelpId(
6264 DWORD dwContextHelpId
)
6267 DECLARE_RETURN(BOOL
);
6269 TRACE("Enter NtUserSetMenuContextHelpId\n");
6270 UserEnterExclusive();
6272 if(!(Menu
= UserGetMenuObject(hMenu
)))
6277 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6280 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6289 NtUserSetMenuDefaultItem(
6295 DECLARE_RETURN(BOOL
);
6297 TRACE("Enter NtUserSetMenuDefaultItem\n");
6298 UserEnterExclusive();
6300 if(!(Menu
= UserGetMenuObject(hMenu
)))
6305 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6308 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6317 NtUserSetMenuFlagRtoL(
6321 DECLARE_RETURN(BOOL
);
6323 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6324 UserEnterExclusive();
6326 if(!(Menu
= UserGetMenuObject(hMenu
)))
6331 RETURN(IntSetMenuFlagRtoL(Menu
));
6334 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6343 NtUserThunkedMenuInfo(
6348 DECLARE_RETURN(BOOL
);
6350 TRACE("Enter NtUserThunkedMenuInfo\n");
6351 UserEnterExclusive();
6353 if (!(Menu
= UserGetMenuObject(hMenu
)))
6358 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6361 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6370 NtUserThunkedMenuItemInfo(
6375 LPMENUITEMINFOW lpmii
,
6376 PUNICODE_STRING lpszCaption
)
6380 UNICODE_STRING lstrCaption
;
6381 DECLARE_RETURN(BOOL
);
6383 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6384 UserEnterExclusive();
6386 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6387 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6389 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6391 if (!(Menu
= UserGetMenuObject(hMenu
)))
6396 /* Check if we got a Caption */
6397 if (lpszCaption
&& lpszCaption
->Buffer
)
6399 /* Copy the string to kernel mode */
6400 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6403 if (!NT_SUCCESS(Status
))
6405 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6406 SetLastNtError(Status
);
6411 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6413 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6416 if (lstrCaption
.Buffer
)
6418 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6421 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6430 NtUserTrackPopupMenuEx(
6442 USER_REFERENCE_ENTRY Ref
;
6444 TRACE("Enter NtUserTrackPopupMenuEx\n");
6445 UserEnterExclusive();
6446 /* Parameter check */
6447 if (!(menu
= UserGetMenuObject( hMenu
)))
6449 ERR("TPME : Invalid Menu handle.\n");
6450 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6454 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6456 ERR("TPME : Invalid Window handle.\n");
6464 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6469 _SEH2_YIELD(goto Exit
);
6473 UserRefObjectCo(pWnd
, &Ref
);
6474 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6475 UserDerefObjectCo(pWnd
);
6478 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);