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
)
602 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
603 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
607 FreeMenuText(pMenu
,item
);
608 if (bRecurse
&& item
->spSubMenu
)
610 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
);
612 ////// Use cAlloced with inc's of 8's....
613 if (--pMenu
->cItems
== 0)
615 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
616 pMenu
->rgItems
= NULL
;
620 while(nPos
< pMenu
->cItems
)
626 pMenu
->rgItems
= DesktopHeapReAlloc(pMenu
->head
.rpdesk
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
631 /**********************************************************************
634 * Insert (allocate) a new item into a menu.
636 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
640 /* Find where to insert new item */
642 if (flags
& MF_BYPOSITION
) {
643 if (pos
> menu
->cItems
)
646 if (!MENU_FindItem( &menu
, &pos
, flags
))
648 if (submenu
) *submenu
= menu
;
649 if (npos
) *npos
= pos
;
654 /* Make sure that MDI system buttons stay on the right side.
655 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
656 * regardless of their id.
659 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
660 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
663 TRACE("inserting at %u flags %x\n", pos
, flags
);
665 /* Create new items array */
667 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
670 WARN("allocation failed\n" );
673 if (menu
->cItems
> 0)
675 /* Copy the old array into the new one */
676 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
677 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
678 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
680 menu
->rgItems
= newItems
;
682 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
683 menu
->cyMenu
= 0; /* force size recalculate */
684 return &newItems
[pos
];
689 _In_ PMENU MenuObject
,
692 PROSMENUITEMINFO ItemInfo
,
693 PUNICODE_STRING lpstr
)
696 PMENU SubMenu
= NULL
;
698 NT_ASSERT(MenuObject
!= NULL
);
700 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
702 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
706 SubMenu
= MenuObject
;
708 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
710 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
712 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
716 /* Force size recalculation! */
718 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
720 TRACE("IntInsertMenuItemToList = %u %i\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
727 _Out_ PHANDLE Handle
,
729 _In_ PDESKTOP Desktop
,
730 _In_ PPROCESSINFO ppi
)
734 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
746 Menu
->cyMax
= 0; /* Default */
747 Menu
->hbrBack
= NULL
; /* No brush */
748 Menu
->dwContextHelpId
= 0; /* Default */
749 Menu
->dwMenuData
= 0; /* Default */
750 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
751 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
752 Menu
->spwndNotify
= NULL
;
753 Menu
->cyMenu
= 0; // Height
754 Menu
->cxMenu
= 0; // Width
755 Menu
->cItems
= 0; // Item count
758 Menu
->cxTextAlign
= 0;
759 Menu
->rgItems
= NULL
;
762 Menu
->TimeToHide
= FALSE
;
768 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
770 PITEM MenuItem
, NewMenuItem
= NULL
;
776 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, (Source
->cItems
+1) * sizeof(ITEM
));
777 if(!NewMenuItem
) return FALSE
;
779 RtlZeroMemory(NewMenuItem
, (Source
->cItems
+1) * sizeof(ITEM
));
781 Destination
->rgItems
= NewMenuItem
;
783 MenuItem
= Source
->rgItems
;
784 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
786 NewMenuItem
->fType
= MenuItem
->fType
;
787 NewMenuItem
->fState
= MenuItem
->fState
;
788 NewMenuItem
->wID
= MenuItem
->wID
;
789 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
790 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
791 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
792 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
793 if (MenuItem
->lpstr
.Length
)
795 NewMenuItem
->lpstr
.Length
= 0;
796 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
797 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
798 if (!NewMenuItem
->lpstr
.Buffer
)
800 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
803 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
804 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
805 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
809 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
810 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
812 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
818 IntCloneMenu(PMENU Source
)
826 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
827 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
829 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
836 Menu
->fFlags
= Source
->fFlags
;
837 Menu
->cyMax
= Source
->cyMax
;
838 Menu
->hbrBack
= Source
->hbrBack
;
839 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
840 Menu
->dwMenuData
= Source
->dwMenuData
;
841 Menu
->iItem
= NO_SELECTED_ITEM
;
842 Menu
->spwndNotify
= NULL
;
845 Menu
->cItems
= Source
->cItems
;
848 Menu
->cxTextAlign
= 0;
849 Menu
->rgItems
= NULL
;
852 Menu
->TimeToHide
= FALSE
;
854 IntCloneMenuItems(Menu
, Source
);
860 IntSetMenuFlagRtoL(PMENU Menu
)
862 ERR("SetMenuFlagRtoL\n");
863 Menu
->fFlags
|= MNF_RTOL
;
868 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
870 Menu
->dwContextHelpId
= dwContextHelpId
;
875 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
877 if(lpmi
->fMask
& MIM_BACKGROUND
)
878 lpmi
->hbrBack
= Menu
->hbrBack
;
879 if(lpmi
->fMask
& MIM_HELPID
)
880 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
881 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
882 lpmi
->cyMax
= Menu
->cyMax
;
883 if(lpmi
->fMask
& MIM_MENUDATA
)
884 lpmi
->dwMenuData
= Menu
->dwMenuData
;
885 if(lpmi
->fMask
& MIM_STYLE
)
886 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
888 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
890 lpmi
->cItems
= Menu
->cItems
;
892 lpmi
->iItem
= Menu
->iItem
;
893 lpmi
->cxMenu
= Menu
->cxMenu
;
894 lpmi
->cyMenu
= Menu
->cyMenu
;
895 lpmi
->spwndNotify
= Menu
->spwndNotify
;
896 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
897 lpmi
->iTop
= Menu
->iTop
;
898 lpmi
->iMaxTop
= Menu
->iMaxTop
;
899 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
901 lpmi
->fFlags
= Menu
->fFlags
;
902 lpmi
->Self
= Menu
->head
.h
;
903 lpmi
->TimeToHide
= Menu
->TimeToHide
;
904 lpmi
->Wnd
= Menu
->hWnd
;
910 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
912 if(lpmi
->fMask
& MIM_BACKGROUND
)
913 Menu
->hbrBack
= lpmi
->hbrBack
;
914 if(lpmi
->fMask
& MIM_HELPID
)
915 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
916 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
917 Menu
->cyMax
= lpmi
->cyMax
;
918 if(lpmi
->fMask
& MIM_MENUDATA
)
919 Menu
->dwMenuData
= lpmi
->dwMenuData
;
920 if(lpmi
->fMask
& MIM_STYLE
)
921 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
922 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
925 PITEM item
= Menu
->rgItems
;
926 for ( i
= Menu
->cItems
; i
; i
--, item
++)
928 if ( item
->spSubMenu
)
930 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
934 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
936 Menu
->iItem
= lpmi
->iItem
;
937 Menu
->cyMenu
= lpmi
->cyMenu
;
938 Menu
->cxMenu
= lpmi
->cxMenu
;
939 Menu
->spwndNotify
= lpmi
->spwndNotify
;
940 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
941 Menu
->iTop
= lpmi
->iTop
;
942 Menu
->iMaxTop
= lpmi
->iMaxTop
;
943 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
945 Menu
->TimeToHide
= lpmi
->TimeToHide
;
946 Menu
->hWnd
= lpmi
->Wnd
;
948 if ( lpmi
->fMask
& MIM_STYLE
)
950 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
951 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
952 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
958 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
959 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
963 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
965 lpmii
->fType
= MenuItem
->fType
;
967 if(lpmii
->fMask
& MIIM_BITMAP
)
969 lpmii
->hbmpItem
= MenuItem
->hbmp
;
971 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
973 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
974 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
976 if(lpmii
->fMask
& MIIM_DATA
)
978 lpmii
->dwItemData
= MenuItem
->dwItemData
;
980 if(lpmii
->fMask
& MIIM_ID
)
982 lpmii
->wID
= MenuItem
->wID
;
984 if(lpmii
->fMask
& MIIM_STATE
)
986 lpmii
->fState
= MenuItem
->fState
;
988 if(lpmii
->fMask
& MIIM_SUBMENU
)
990 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
993 if ((lpmii
->fMask
& MIIM_STRING
) ||
994 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
996 if (lpmii
->dwTypeData
== NULL
)
998 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1001 { //// lpmii->lpstr can be read in user mode!!!!
1002 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1003 min(lpmii
->cch
* sizeof(WCHAR
),
1004 MenuItem
->lpstr
.MaximumLength
));
1005 if (! NT_SUCCESS(Status
))
1007 SetLastNtError(Status
);
1013 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1015 lpmii
->Rect
.left
= MenuItem
->xItem
;
1016 lpmii
->Rect
.top
= MenuItem
->yItem
;
1017 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1018 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1019 lpmii
->dxTab
= MenuItem
->dxTab
;
1020 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1021 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1022 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1029 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1031 PMENU SubMenuObject
;
1032 BOOL circref
= FALSE
;
1034 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1038 if ( lpmii
->fMask
& MIIM_FTYPE
)
1040 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1041 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1043 if (lpmii
->fMask
& MIIM_TYPE
)
1045 #if 0 //// Done in User32.
1046 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1048 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1049 KeRosDumpStackFrames(NULL
, 20);
1050 /* This does not happen on Win9x/ME */
1051 SetLastNtError( ERROR_INVALID_PARAMETER
);
1056 * Delete the menu item type when changing type from
1059 if (MenuItem
->fType
!= lpmii
->fType
&&
1060 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1062 FreeMenuText(MenuObject
,MenuItem
);
1063 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1064 MenuItem
->Xlpstr
= NULL
;
1066 if(lpmii
->fType
& MFT_BITMAP
)
1069 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1071 { /* Win 9x/Me stuff */
1072 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1074 lpmii
->dwTypeData
= 0;
1077 if(lpmii
->fMask
& MIIM_BITMAP
)
1079 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1080 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1081 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1083 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1085 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1087 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1088 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1090 if(lpmii
->fMask
& MIIM_DATA
)
1092 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1094 if(lpmii
->fMask
& MIIM_ID
)
1096 MenuItem
->wID
= lpmii
->wID
;
1098 if(lpmii
->fMask
& MIIM_STATE
)
1100 /* Remove MFS_DEFAULT flag from all other menu items if this item
1101 has the MFS_DEFAULT state */
1102 if(lpmii
->fState
& MFS_DEFAULT
)
1103 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1104 /* Update the menu item state flags */
1105 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1108 if(lpmii
->fMask
& MIIM_SUBMENU
)
1110 if (lpmii
->hSubMenu
)
1112 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1113 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1115 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1117 if (MenuObject
== SubMenuObject
)
1120 ERR("Pop Up Menu Double Trouble!\n");
1121 SubMenuObject
= IntCreateMenu(&hMenu
,
1123 MenuObject
->head
.rpdesk
,
1124 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1125 if (!SubMenuObject
) return FALSE
;
1126 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1129 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1131 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1132 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1135 /* Make sure the submenu is marked as a popup menu */
1136 SubMenuObject
->fFlags
|= MNF_POPUP
;
1137 // Now fix the test_subpopup_locked_by_menu tests....
1138 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1139 MenuItem
->spSubMenu
= SubMenuObject
;
1140 UserReferenceObject(SubMenuObject
);
1144 EngSetLastError( ERROR_INVALID_PARAMETER
);
1149 { // If submenu just dereference it.
1150 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1151 MenuItem
->spSubMenu
= NULL
;
1155 if ((lpmii
->fMask
& MIIM_STRING
) ||
1156 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1158 /* free the string when used */
1159 FreeMenuText(MenuObject
,MenuItem
);
1160 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1161 MenuItem
->Xlpstr
= NULL
;
1163 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1165 UNICODE_STRING Source
;
1167 Source
.Length
= Source
.MaximumLength
= lpmii
->cch
* sizeof(WCHAR
);
1168 Source
.Buffer
= lpmii
->dwTypeData
;
1170 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1171 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1173 MenuItem
->lpstr
.Length
= 0;
1174 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1175 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1176 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1178 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1179 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1184 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1185 !MenuItem
->Xlpstr
&&
1186 !lpmii
->dwTypeData
&&
1187 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1189 MenuItem
->fType
|= MFT_SEPARATOR
;
1191 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1193 MenuItem
->xItem
= lpmii
->Rect
.left
;
1194 MenuItem
->yItem
= lpmii
->Rect
.top
;
1195 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1196 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1197 MenuItem
->dxTab
= lpmii
->dxTab
;
1198 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1199 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1200 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1208 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1213 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1215 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1217 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1219 /* If the close item in the system menu change update the close button */
1222 switch (MenuItem
->wID
) // More than just close.
1230 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1232 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1234 /* Refresh the frame to reflect the change */
1235 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1237 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1240 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1250 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1255 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1257 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1259 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1265 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1268 PITEM MenuItem
= MenuObject
->rgItems
;
1270 if (!MenuItem
) return FALSE
;
1272 /* reset all default-item flags */
1273 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1275 MenuItem
->fState
&= ~MFS_DEFAULT
;
1278 /* no default item */
1279 if(uItem
== (UINT
)-1)
1283 MenuItem
= MenuObject
->rgItems
;
1286 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1287 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1292 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1294 if (MenuItem
->wID
== uItem
)
1296 MenuItem
->fState
|= MFS_DEFAULT
;
1306 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1309 PITEM MenuItem
= MenuObject
->rgItems
;
1312 if (!MenuItem
) return -1;
1314 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1317 if (i
>= MenuObject
->cItems
) return -1;
1320 /* default: don't return disabled items */
1321 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1323 /* search rekursiv when needed */
1324 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1328 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1330 if ( -1 != ret
) return ret
;
1332 /* when item not found in submenu, return the popup item */
1334 return ( fByPos
) ? i
: MenuItem
->wID
;
1344 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1345 return pItem
->spSubMenu
;
1348 /***********************************************************************
1349 * MenuInitSysMenuPopup
1351 * Grey the appropriate items in System menu.
1353 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1358 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1359 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1360 gray
= ((style
& WS_MAXIMIZE
) != 0);
1361 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1362 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1363 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1364 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1365 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1366 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1367 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1368 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1370 /* The menu item must keep its state if it's disabled */
1372 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1374 /* Set default menu item */
1375 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1376 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1377 else DefItem
= SC_CLOSE
;
1379 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1383 /***********************************************************************
1384 * MenuDrawPopupGlyph
1386 * Draws popup magic glyphs (can be found in system menu).
1388 static void FASTCALL
1389 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1392 HFONT hFont
, hOldFont
;
1398 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1401 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1404 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1407 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1411 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1414 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1415 RECTL_vInflateRect(r
, -2, -2);
1416 lf
.lfHeight
= r
->bottom
- r
->top
;
1418 lf
.lfWeight
= FW_NORMAL
;
1419 lf
.lfCharSet
= DEFAULT_CHARSET
;
1420 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1421 hFont
= GreCreateFontIndirectW(&lf
);
1422 /* save font and text color */
1423 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1424 clrsave
= GreGetTextColor(dc
);
1425 bkmode
= GreGetBkMode(dc
);
1426 /* set color and drawing mode */
1427 IntGdiSetBkMode(dc
, TRANSPARENT
);
1433 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1434 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1437 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1438 /* draw selected symbol */
1439 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1440 /* restore previous settings */
1441 IntGdiSetTextColor(dc
, clrsave
);
1442 NtGdiSelectFont(dc
, hOldFont
);
1443 IntGdiSetBkMode(dc
, bkmode
);
1444 GreDeleteObject(hFont
);
1447 /***********************************************************************
1448 * MENU_AdjustMenuItemRect
1450 * Adjust menu item rectangle according to scrolling state.
1453 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1455 if (menu
->dwArrowsOn
)
1457 UINT arrow_bitmap_height
;
1458 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1459 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1460 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1464 /***********************************************************************
1465 * MENU_FindItemByCoords
1467 * Find the item at the specified coordinates (screen coords). Does
1468 * not work for child windows and therefore should not be called for
1469 * an arbitrary system menu.
1471 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1476 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1478 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1479 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1480 pt
.x
= rect
.right
- 1 - pt
.x
;
1484 item
= menu
->rgItems
;
1485 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1487 //rect = item->rect;
1488 rect
.left
= item
->xItem
;
1489 rect
.top
= item
->yItem
;
1490 rect
.right
= item
->cxItem
; // Do this for now......
1491 rect
.bottom
= item
->cyItem
;
1493 MENU_AdjustMenuItemRect(menu
, &rect
);
1494 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1503 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1505 MENU
*menu
= UserGetMenuObject(hMenu
);
1508 /*FIXME: Do we have to handle hWnd here? */
1509 if (!menu
) return -1;
1510 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1514 /***********************************************************************
1517 * Find the menu item selected by a key press.
1518 * Return item id, -1 if none, -2 if we should close the menu.
1520 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1521 WCHAR Key
, BOOL ForceMenuChar
)
1526 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1528 if (!menu
|| !VerifyMenu(menu
))
1529 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1532 ITEM
*item
= menu
->rgItems
;
1534 if ( !ForceMenuChar
)
1537 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1539 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1541 LPWSTR text
= item
->Xlpstr
;
1544 const WCHAR
*p
= text
- 2;
1547 const WCHAR
*q
= p
+ 2;
1548 p
= wcschr (q
, '&');
1549 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1551 while (p
!= NULL
&& p
[1] == '&');
1552 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1557 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1558 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1560 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1561 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1562 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1563 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1568 /***********************************************************************
1569 * MenuGetBitmapItemSize
1571 * Get the size of a bitmap item.
1573 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1576 HBITMAP bmp
= lpitem
->hbmp
;
1578 size
->cx
= size
->cy
= 0;
1580 /* check if there is a magic menu item associated with this item */
1581 if (IS_MAGIC_BITMAP(bmp
))
1583 switch((INT_PTR
) bmp
)
1585 case (INT_PTR
)HBMMENU_CALLBACK
:
1587 MEASUREITEMSTRUCT measItem
;
1588 measItem
.CtlType
= ODT_MENU
;
1590 measItem
.itemID
= lpitem
->wID
;
1591 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1592 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1593 measItem
.itemData
= lpitem
->dwItemData
;
1594 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1595 size
->cx
= measItem
.itemWidth
;
1596 size
->cy
= measItem
.itemHeight
;
1597 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1602 case (INT_PTR
) HBMMENU_SYSTEM
:
1603 if (lpitem
->dwItemData
)
1605 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1609 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1610 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1611 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1612 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1613 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1614 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1615 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1616 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1617 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1618 /* FIXME: Why we need to subtract these magic values? */
1619 /* to make them smaller than the menu bar? */
1620 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1621 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1626 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1628 size
->cx
= bm
.bmWidth
;
1629 size
->cy
= bm
.bmHeight
;
1633 /***********************************************************************
1634 * MenuDrawBitmapItem
1636 * Draw a bitmap item.
1638 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1639 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1645 int w
= rect
->right
- rect
->left
;
1646 int h
= rect
->bottom
- rect
->top
;
1647 int bmp_xoffset
= 0;
1649 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1652 /* Check if there is a magic menu item associated with this item */
1653 if (IS_MAGIC_BITMAP(hbmToDraw
))
1659 switch ((INT_PTR
)hbmToDraw
)
1661 case (INT_PTR
)HBMMENU_SYSTEM
:
1662 if (lpitem
->dwItemData
)
1664 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1666 ERR("Get Item Data from this Window!!!\n");
1669 ERR("Draw Bitmap\n");
1670 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1671 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1675 PCURICON_OBJECT pIcon
= NULL
;
1676 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1678 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1679 /* only use right half of the bitmap */
1680 //bmp_xoffset = bm.bmWidth / 2;
1681 //bm.bmWidth -= bmp_xoffset;
1684 pIcon
= NC_IconForWindow(WndOwner
);
1685 // FIXME: NC_IconForWindow should reference it for us */
1686 if (pIcon
) UserReferenceObject(pIcon
);
1691 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1692 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1693 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1694 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1695 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1696 UserDereferenceObject(pIcon
);
1701 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1702 flags
= DFCS_CAPTIONRESTORE
;
1704 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1706 flags
= DFCS_CAPTIONMIN
;
1708 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1710 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1712 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1713 flags
= DFCS_CAPTIONCLOSE
;
1715 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1716 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1718 case (INT_PTR
)HBMMENU_CALLBACK
:
1720 DRAWITEMSTRUCT drawItem
;
1722 drawItem
.CtlType
= ODT_MENU
;
1724 drawItem
.itemID
= lpitem
->wID
;
1725 drawItem
.itemAction
= odaction
;
1726 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1727 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1728 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1729 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1730 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1731 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1732 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1733 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1735 drawItem
.rcItem
= *rect
;
1736 drawItem
.itemData
= lpitem
->dwItemData
;
1737 /* some applications make this assumption on the DC's origin */
1738 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1739 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1740 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1741 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1746 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1747 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1748 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1749 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1750 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1753 RECTL_vInflateRect(&r
, -1, -1);
1754 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1755 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1759 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1762 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1763 NtGdiSelectBitmap( hdcMem
, bmp
);
1764 /* handle fontsize > bitmap_height */
1765 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1767 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1768 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1769 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1770 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1771 IntGdiDeleteDC( hdcMem
, FALSE
);
1775 IntGetDialogBaseUnits(VOID
)
1784 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1786 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1787 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1788 UserReleaseDC( 0, hdc
, FALSE
);
1795 /***********************************************************************
1798 * Calculate the size of the menu item and store it in lpitem->rect.
1800 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1801 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1804 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1805 UINT arrow_bitmap_width
;
1809 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1811 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1813 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1815 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1817 if (lpitem
->fType
& MF_OWNERDRAW
)
1819 MEASUREITEMSTRUCT mis
;
1820 mis
.CtlType
= ODT_MENU
;
1822 mis
.itemID
= lpitem
->wID
;
1823 mis
.itemData
= lpitem
->dwItemData
;
1824 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1826 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1827 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1828 * width of a menufont character to the width of an owner-drawn menu.
1830 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1832 /* under at least win95 you seem to be given a standard
1833 height for the menu and the height value is ignored */
1834 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1836 Rect
.bottom
+= mis
.itemHeight
;
1838 //lpitem->cxBmp = mis.itemWidth;
1839 //lpitem->cyBmp = mis.itemHeight;
1840 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1841 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1842 lpitem
->wID
, Rect
.right
-Rect
.left
,
1843 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1845 lpitem
->xItem
= Rect
.left
;
1846 lpitem
->yItem
= Rect
.top
;
1847 lpitem
->cxItem
= Rect
.right
;
1848 lpitem
->cyItem
= Rect
.bottom
;
1853 lpitem
->xItem
= orgX
;
1854 lpitem
->yItem
= orgY
;
1855 lpitem
->cxItem
= orgX
;
1856 lpitem
->cyItem
= orgY
;
1858 if (lpitem
->fType
& MF_SEPARATOR
)
1860 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1862 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1873 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1874 /* Keep the size of the bitmap in callback mode to be able
1875 * to draw it correctly */
1876 lpitem
->cxBmp
= size
.cx
;
1877 lpitem
->cyBmp
= size
.cy
;
1878 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1879 lpitem
->cxItem
+= size
.cx
+ 2;
1880 itemheight
= size
.cy
+ 2;
1882 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1883 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1884 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1885 lpitem
->dxTab
= lpitem
->cxItem
;
1886 lpitem
->cxItem
+= arrow_bitmap_width
;
1887 } else /* hbmpItem & MenuBar */ {
1888 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1889 lpitem
->cxItem
+= size
.cx
;
1890 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1891 itemheight
= size
.cy
;
1893 /* Special case: Minimize button doesn't have a space behind it. */
1894 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1895 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1896 lpitem
->cxItem
-= 1;
1899 else if (!menuBar
) {
1900 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1901 lpitem
->cxItem
+= check_bitmap_width
;
1902 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1903 lpitem
->dxTab
= lpitem
->cxItem
;
1904 lpitem
->cxItem
+= arrow_bitmap_width
;
1907 /* it must be a text item - unless it's the system menu */
1908 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1909 HFONT hfontOld
= NULL
;
1910 RECT rc
;// = lpitem->Rect;
1911 LONG txtheight
, txtwidth
;
1913 rc
.left
= lpitem
->xItem
;
1914 rc
.top
= lpitem
->yItem
;
1915 rc
.right
= lpitem
->cxItem
; // Do this for now......
1916 rc
.bottom
= lpitem
->cyItem
;
1918 if ( lpitem
->fState
& MFS_DEFAULT
) {
1919 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1922 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1924 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1925 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1927 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1929 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1932 int n
= (int)( p
- lpitem
->Xlpstr
);
1933 /* Item contains a tab (only meaningful in popup menus) */
1934 /* get text size before the tab */
1935 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1936 DT_SINGLELINE
|DT_CALCRECT
);
1937 txtwidth
= rc
.right
- rc
.left
;
1938 p
+= 1; /* advance past the Tab */
1939 /* get text size after the tab */
1940 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1941 DT_SINGLELINE
|DT_CALCRECT
);
1942 lpitem
->dxTab
+= txtwidth
;
1943 txtheight
= max( txtheight
, tmpheight
);
1944 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1945 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1947 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1948 DT_SINGLELINE
|DT_CALCRECT
);
1949 txtwidth
= rc
.right
- rc
.left
;
1950 lpitem
->dxTab
+= txtwidth
;
1952 lpitem
->cxItem
+= 2 + txtwidth
;
1953 itemheight
= max( itemheight
,
1954 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1958 NtGdiSelectFont (hdc
, hfontOld
);
1960 } else if( menuBar
) {
1961 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1963 lpitem
->cyItem
+= itemheight
;
1964 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1967 /***********************************************************************
1968 * MENU_GetMaxPopupHeight
1971 MENU_GetMaxPopupHeight(PMENU lppop
)
1975 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1976 return lppop
->cyMax
;
1978 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
1979 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
1982 /***********************************************************************
1983 * MenuPopupMenuCalcSize
1985 * Calculate the size of a popup menu.
1987 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
1992 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1993 BOOL textandbmp
= FALSE
;
1995 Menu
->cxMenu
= Menu
->cyMenu
= 0;
1996 if (Menu
->cItems
== 0) return;
1998 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2000 NtGdiSelectFont( hdc
, ghMenuFont
);
2005 Menu
->cxTextAlign
= 0;
2007 while (start
< Menu
->cItems
)
2009 lpitem
= &Menu
->rgItems
[start
];
2011 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2012 orgX
+= MENU_COL_SPACE
;
2013 orgY
= MENU_TOP_MARGIN
;
2015 maxTab
= maxTabWidth
= 0;
2016 /* Parse items until column break or end of menu */
2017 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2020 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2022 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2023 maxX
= max(maxX
, lpitem
->cxItem
);
2024 orgY
= lpitem
->cyItem
;
2025 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2027 maxTab
= max( maxTab
, lpitem
->dxTab
);
2028 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2030 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2033 /* Finish the column (set all items to the largest width found) */
2034 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2035 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2037 lpitem
->cxItem
= maxX
;
2038 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2039 lpitem
->dxTab
= maxTab
;
2041 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2044 Menu
->cxMenu
= maxX
;
2045 /* if none of the items have both text and bitmap then
2046 * the text and bitmaps are all aligned on the left. If there is at
2047 * least one item with both text and bitmap then bitmaps are
2048 * on the left and texts left aligned with the right hand side
2050 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2052 /* space for 3d border */
2053 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2056 /* Adjust popup height if it exceeds maximum */
2057 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2058 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2059 if (Menu
->cyMenu
>= maxHeight
)
2061 Menu
->cyMenu
= maxHeight
;
2062 Menu
->dwArrowsOn
= 1;
2066 Menu
->dwArrowsOn
= 0;
2068 UserReleaseDC( 0, hdc
, FALSE
);
2071 /***********************************************************************
2072 * MENU_MenuBarCalcSize
2074 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2075 * height is off by 1 pixel which causes lengthy window relocations when
2076 * active document window is maximized/restored.
2078 * Calculate the size of the menu bar.
2080 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2083 UINT start
, i
, helpPos
;
2084 int orgX
, orgY
, maxY
;
2086 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2087 if (lppop
->cItems
== 0) return;
2088 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2089 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2091 maxY
= lprect
->top
+1;
2094 lppop
->cxTextAlign
= 0;
2095 while (start
< lppop
->cItems
)
2097 lpitem
= &lppop
->rgItems
[start
];
2098 orgX
= lprect
->left
;
2101 /* Parse items until line break or end of menu */
2102 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2104 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2106 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2108 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2109 //debug_print_menuitem (" item: ", lpitem, "");
2110 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2111 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2113 if (lpitem
->cxItem
> lprect
->right
)
2115 if (i
!= start
) break;
2116 else lpitem
->cxItem
= lprect
->right
;
2118 maxY
= max( maxY
, lpitem
->cyItem
);
2119 orgX
= lpitem
->cxItem
;
2122 /* Finish the line (set all items to the largest height found) */
2124 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2125 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2127 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2129 start
= i
; /* This works! */
2132 lprect
->bottom
= maxY
;
2133 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2135 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2136 /* the last item (if several lines, only move the last line) */
2137 if (helpPos
== ~0U) return;
2138 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2139 orgY
= lpitem
->yItem
;
2140 orgX
= lprect
->right
;
2141 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2142 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2143 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2144 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2145 lpitem
->cxItem
= orgX
;
2146 orgX
= lpitem
->xItem
;
2150 /***********************************************************************
2151 * MENU_DrawScrollArrows
2153 * Draw scroll arrows.
2155 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2157 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2161 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2162 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2166 rect
.right
= lppop
->cxMenu
;
2167 rect
.bottom
= arrow_bitmap_height
;
2168 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2169 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2171 dfcrc
.right
= arrow_bitmap_width
;
2172 dfcrc
.bottom
= arrow_bitmap_height
;
2173 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2175 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2176 rect
.bottom
= lppop
->cyMenu
;
2177 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2178 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2179 Flags
= DFCS_INACTIVE
;
2180 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2181 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2182 dfcrc
.right
= arrow_bitmap_width
;
2183 dfcrc
.bottom
= lppop
->cyMenu
;
2184 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2187 /***********************************************************************
2190 * Draw a single menu item.
2192 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2193 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2197 BOOL flat_menu
= FALSE
;
2199 UINT arrow_bitmap_width
= 0;
2203 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2206 if (lpitem
->fType
& MF_SYSMENU
)
2208 if (!(Wnd
->style
& WS_MINIMIZE
))
2210 NC_GetInsideRect(Wnd
, &rect
);
2211 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2216 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2217 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2221 if (lpitem
->fState
& MF_HILITE
)
2223 if(menuBar
&& !flat_menu
) {
2224 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2225 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2227 if (lpitem
->fState
& MF_GRAYED
)
2228 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2230 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2231 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2236 if (lpitem
->fState
& MF_GRAYED
)
2237 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2239 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2240 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2243 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2244 //rect = lpitem->Rect;
2245 rect
.left
= lpitem
->xItem
;
2246 rect
.top
= lpitem
->yItem
;
2247 rect
.right
= lpitem
->cxItem
; // Do this for now......
2248 rect
.bottom
= lpitem
->cyItem
;
2250 MENU_AdjustMenuItemRect(Menu
, &rect
);
2252 if (lpitem
->fType
& MF_OWNERDRAW
)
2255 ** Experimentation under Windows reveals that an owner-drawn
2256 ** menu is given the rectangle which includes the space it requested
2257 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2258 ** and a popup-menu arrow. This is the value of lpitem->rect.
2259 ** Windows will leave all drawing to the application except for
2260 ** the popup-menu arrow. Windows always draws that itself, after
2261 ** the menu owner has finished drawing.
2264 COLORREF old_bk
, old_text
;
2266 dis
.CtlType
= ODT_MENU
;
2268 dis
.itemID
= lpitem
->wID
;
2269 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2271 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2272 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2273 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2274 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2275 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2276 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2277 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2278 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2279 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2282 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2283 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2284 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2285 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2287 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2288 old_bk
= GreGetBkColor(hdc
);
2289 old_text
= GreGetTextColor(hdc
);
2290 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2291 IntGdiSetBkColor(hdc
, old_bk
);
2292 IntGdiSetTextColor(hdc
, old_text
);
2293 /* Draw the popup-menu arrow */
2294 if (!menuBar
&& lpitem
->spSubMenu
)
2297 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2298 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2299 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2304 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2306 if (lpitem
->fState
& MF_HILITE
)
2310 RECTL_vInflateRect (&rect
, -1, -1);
2311 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2312 RECTL_vInflateRect (&rect
, 1, 1);
2313 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2318 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2320 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2324 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2326 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2328 /* vertical separator */
2329 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2334 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2336 rc
.bottom
= Height
- 3;
2339 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2340 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2341 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2342 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2343 NtGdiSelectPen( hdc
, oldPen
);
2346 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2349 /* horizontal separator */
2350 if (lpitem
->fType
& MF_SEPARATOR
)
2357 rc
.top
= ( rc
.top
+ rc
.bottom
) / 2;
2360 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2361 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2362 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2363 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2364 NtGdiSelectPen( hdc
, oldPen
);
2367 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2371 /* helper lines for debugging */
2372 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2373 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2374 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2375 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2376 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2377 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2379 #if 0 // breaks mdi menu bar icons.
2381 /* calculate the bitmap rectangle in coordinates relative
2382 * to the item rectangle */
2384 if( lpitem
->hbmp
== HBMMENU_CALLBACK
)
2387 bmprc
.left
= lpitem
->Xlpstr
? MenuCharSize
.cx
: 0;
2389 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)
2391 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)
2394 bmprc
.left
= 4 + UserGetSystemMetrics(SM_CXMENUCHECK
);
2396 bmprc
.right
= bmprc
.left
+ lpitem
->cxBmp
;
2398 if( menuBar
&& !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2401 bmprc
.top
= (rect
.bottom
- rect
.top
- lpitem
->cyBmp
) / 2;
2403 bmprc
.bottom
= bmprc
.top
+ lpitem
->cyBmp
;
2409 INT y
= rect
.top
+ rect
.bottom
;
2411 BOOL checked
= FALSE
;
2412 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2413 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2414 /* Draw the check mark
2417 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2419 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2420 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2421 lpitem
->hbmpUnchecked
;
2422 if (bm
) /* we have a custom bitmap */
2424 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2426 NtGdiSelectBitmap( hdcMem
, bm
);
2427 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2428 check_bitmap_width
, check_bitmap_height
,
2429 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2430 IntGdiDeleteDC( hdcMem
, FALSE
);
2433 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2437 r
.right
= r
.left
+ check_bitmap_width
;
2438 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2439 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2440 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2444 if ( lpitem
->hbmp
)//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2446 RECT bmpRect
= rect
;
2447 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2448 bmpRect
.left
+= check_bitmap_width
+ 2;
2449 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2451 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2452 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2455 /* Draw the popup-menu arrow */
2456 if (lpitem
->spSubMenu
)
2459 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2460 rectTemp
.left
= rectTemp
.right
- check_bitmap_width
;
2461 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2464 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2465 rect
.left
+= check_bitmap_width
;
2466 rect
.right
-= arrow_bitmap_width
;
2468 else if( lpitem
->hbmp
)
2469 { /* Draw the bitmap */
2470 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
/*bmprc*/, Menu
, WndOwner
, odaction
, menuBar
);
2473 /* process text if present */
2479 UINT uFormat
= menuBar
?
2480 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2481 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2483 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2484 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2486 rect
.left
+= Menu
->cxTextAlign
;
2488 if ( lpitem
->fState
& MFS_DEFAULT
)
2490 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2495 rect
.left
+= lpitem
->cxBmp
;
2496 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2497 rect
.left
+= MenuCharSize
.cx
;
2498 rect
.right
-= MenuCharSize
.cx
;
2501 Text
= lpitem
->Xlpstr
;
2504 for (i
= 0; Text
[i
]; i
++)
2505 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2509 if(lpitem
->fState
& MF_GRAYED
)
2511 if (!(lpitem
->fState
& MF_HILITE
) )
2513 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2514 IntGdiSetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
2515 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2516 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2518 IntGdiSetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
2520 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2522 /* paint the shortcut text */
2523 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2525 if (L
'\t' == Text
[i
])
2527 rect
.left
= lpitem
->dxTab
;
2528 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2532 rect
.right
= lpitem
->dxTab
;
2533 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2536 if (lpitem
->fState
& MF_GRAYED
)
2538 if (!(lpitem
->fState
& MF_HILITE
) )
2540 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2541 IntGdiSetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
2542 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2543 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2545 IntGdiSetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
2547 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2552 NtGdiSelectFont (hdc
, hfontOld
);
2557 /***********************************************************************
2560 * Paint a popup menu.
2562 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2564 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2567 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2569 IntGetClientRect( wnd
, &rect
);
2571 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2572 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2573 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2577 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2579 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2582 BOOL flat_menu
= FALSE
;
2584 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2586 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2588 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2590 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2591 /* draw menu items */
2592 if (menu
&& menu
->cItems
)
2597 item
= menu
->rgItems
;
2598 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2600 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2601 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2603 /* draw scroll arrows */
2604 if (menu
->dwArrowsOn
)
2606 MENU_DrawScrollArrows(menu
, hdc
);
2612 NtGdiSelectBrush( hdc
, hPrevBrush
);
2617 /**********************************************************************
2620 PWND
MENU_IsMenuActive(VOID
)
2622 return ValidateHwndNoErr(top_popup
);
2625 /**********************************************************************
2628 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2630 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2632 void MENU_EndMenu( PWND pwnd
)
2635 menu
= UserGetMenuObject(top_popup_hmenu
);
2636 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2638 if (fInsideMenuLoop
&& top_popup
)
2640 fInsideMenuLoop
= FALSE
;
2644 ERR("Already in End loop\n");
2649 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2655 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2658 HFONT FontOld
= NULL
;
2659 BOOL flat_menu
= FALSE
;
2661 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2665 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2673 if (Rect
== NULL
|| !pMenu
)
2675 return UserGetSystemMetrics(SM_CYMENU
);
2678 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2680 FontOld
= NtGdiSelectFont(hDC
, Font
);
2682 if (pMenu
->cyMenu
== 0)
2684 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2687 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2689 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2691 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2692 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2693 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2694 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2696 if (pMenu
->cItems
== 0)
2698 NtGdiSelectFont(hDC
, FontOld
);
2699 return UserGetSystemMetrics(SM_CYMENU
);
2702 for (i
= 0; i
< pMenu
->cItems
; i
++)
2704 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2707 NtGdiSelectFont(hDC
, FontOld
);
2709 return pMenu
->cyMenu
;
2712 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2715 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2719 // No menu. Do not reserve any space
2725 return UserGetSystemMetrics(SM_CYMENU
);
2730 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2732 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2734 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2736 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2738 return lppop
->cyMenu
;
2742 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2746 /***********************************************************************
2749 * Popup menu initialization before WM_ENTERMENULOOP.
2751 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2754 PPOPUPMENU pPopupMenu
;
2756 LARGE_STRING WindowName
;
2757 UNICODE_STRING ClassName
;
2758 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2760 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2762 menu
->spwndNotify
= pWndOwner
;
2764 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2765 ex_style
= WS_EX_LAYOUTRTL
;
2767 ClassName
.Buffer
= WC_MENU
;
2768 ClassName
.Length
= 0;
2770 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2771 RtlZeroMemory(&Cs
, sizeof(Cs
));
2772 Cs
.style
= WS_POPUP
;
2773 Cs
.dwExStyle
= ex_style
;
2774 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2775 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2776 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2777 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2778 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2780 /* NOTE: In Windows, top menu popup is not owned. */
2781 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2783 if( !pWndCreated
) return FALSE
;
2786 // Setup pop up menu structure.
2788 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2790 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2792 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2793 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2794 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2796 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2797 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2798 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2799 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2800 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2802 if (pPopupMenu
->fRightButton
)
2803 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2805 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2807 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2808 menu
->fFlags
& MNF_RTOL
)
2810 pPopupMenu
->fDroppedLeft
= TRUE
;
2815 /***********************************************************************
2818 * Display a popup menu.
2820 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2821 INT x
, INT y
, INT xanchor
, INT yanchor
)
2827 USER_REFERENCE_ENTRY Ref
;
2829 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2830 pwndOwner
, menu
, id
, x
, y
, xanchor
, yanchor
);
2832 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2834 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2835 menu
->iItem
= NO_SELECTED_ITEM
;
2838 menu
->dwArrowsOn
= 0;
2839 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2841 /* adjust popup menu pos so that it fits within the desktop */
2843 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2844 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2846 /* FIXME: should use item rect */
2849 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2851 if (flags
& TPM_LAYOUTRTL
)
2852 flags
^= TPM_RIGHTALIGN
;
2854 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2855 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2857 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2858 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2860 if( x
+ width
> monitor
->rcMonitor
.right
)
2862 if( xanchor
&& x
>= width
- xanchor
)
2863 x
-= width
- xanchor
;
2865 if( x
+ width
> monitor
->rcMonitor
.right
)
2866 x
= monitor
->rcMonitor
.right
- width
;
2868 if( x
< monitor
->rcMonitor
.left
) x
= monitor
->rcMonitor
.left
;
2870 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2872 if( yanchor
&& y
>= height
+ yanchor
)
2873 y
-= height
+ yanchor
;
2875 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2876 y
= monitor
->rcMonitor
.bottom
- height
;
2878 if( y
< monitor
->rcMonitor
.top
) y
= monitor
->rcMonitor
.top
;
2880 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2884 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2889 top_popup
= menu
->hWnd
;
2890 top_popup_hmenu
= UserHMGetHandle(menu
);
2893 /* Display the window */
2894 UserRefObjectCo(pWnd
, &Ref
);
2895 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2897 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2899 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2900 UserDerefObjectCo(pWnd
);
2905 /***********************************************************************
2906 * MENU_EnsureMenuItemVisible
2908 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2910 USER_REFERENCE_ENTRY Ref
;
2911 if (lppop
->dwArrowsOn
)
2913 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2914 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2915 UINT nOldPos
= lppop
->iTop
;
2917 UINT arrow_bitmap_height
;
2918 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2920 IntGetClientRect(pWnd
, &rc
);
2922 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2924 rc
.top
+= arrow_bitmap_height
;
2925 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2927 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2928 UserRefObjectCo(pWnd
, &Ref
);
2929 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
2931 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
2932 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2933 MENU_DrawScrollArrows(lppop
, hdc
);
2934 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2936 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
2938 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
2939 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2940 MENU_DrawScrollArrows(lppop
, hdc
);
2941 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2943 UserDerefObjectCo(pWnd
);
2947 /***********************************************************************
2950 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
2951 BOOL sendMenuSelect
, PMENU topmenu
)
2956 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2958 if (!menu
|| !menu
->cItems
) return;
2960 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
2964 if (menu
->iItem
== wIndex
) return;
2966 if (menu
->fFlags
& MNF_POPUP
)
2967 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
2969 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2972 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
2973 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
2974 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
2977 NtGdiSelectFont( hdc
, ghMenuFont
);
2979 /* Clear previous highlighted item */
2980 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2982 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2983 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
2984 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
2988 /* Highlight new item (if any) */
2989 menu
->iItem
= wIndex
;
2990 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2992 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
2994 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
2995 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
2996 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
2997 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3001 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3002 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3003 ip
->fType
| ip
->fState
|
3004 (ip
->spSubMenu
? MF_POPUP
: 0) |
3005 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3007 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3010 else if (sendMenuSelect
)
3015 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3016 if (pos
!= NO_SELECTED_ITEM
)
3018 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3019 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3020 (ip
->spSubMenu
? MF_POPUP
: 0) |
3021 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3023 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3027 UserReleaseDC(pWnd
, hdc
, FALSE
);
3030 /***********************************************************************
3033 * Moves currently selected item according to the Offset parameter.
3034 * If there is no selection then it should select the last item if
3035 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3037 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3041 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3043 if ((!menu
) || (!menu
->rgItems
)) return;
3045 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3047 if ( menu
->cItems
== 1 )
3050 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3052 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3054 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3059 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3060 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3061 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3063 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3068 /***********************************************************************
3071 * Hide the sub-popup menus of this menu.
3073 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3074 BOOL SendMenuSelect
, UINT wFlags
)
3076 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3078 if ( Menu
&& top_popup
)
3082 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3084 Item
= &Menu
->rgItems
[Menu
->iItem
];
3085 if (!(Item
->spSubMenu
) ||
3086 !(Item
->fState
& MF_MOUSESELECT
)) return;
3087 Item
->fState
&= ~MF_MOUSESELECT
;
3092 if (Item
->spSubMenu
)
3095 if (!VerifyMenu(Item
->spSubMenu
)) return;
3096 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3097 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3098 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3099 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3100 co_UserDestroyWindow(pWnd
);
3102 /* Native returns handle to destroyed window */
3103 if (!(wFlags
& TPM_NONOTIFY
))
3105 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3106 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3109 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3110 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3112 Item
->spSubMenu
->hWnd
= NULL
;
3118 /***********************************************************************
3121 * Display the sub-menu of the selected item of this menu.
3122 * Return the handle of the submenu, or menu if no submenu to display.
3124 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3131 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3133 if (!Menu
) return Menu
;
3135 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3137 Item
= &Menu
->rgItems
[Menu
->iItem
];
3138 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3141 /* message must be sent before using item,
3142 because nearly everything may be changed by the application ! */
3144 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3145 if (!(Flags
& TPM_NONOTIFY
))
3147 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3148 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3149 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3152 Item
= &Menu
->rgItems
[Menu
->iItem
];
3153 //Rect = ItemInfo.Rect;
3154 Rect
.left
= Item
->xItem
;
3155 Rect
.top
= Item
->yItem
;
3156 Rect
.right
= Item
->cxItem
; // Do this for now......
3157 Rect
.bottom
= Item
->cyItem
;
3159 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3161 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3162 if (!(Item
->fState
& MF_HILITE
))
3164 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3165 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3167 NtGdiSelectFont(Dc
, ghMenuFont
);
3169 Item
->fState
|= MF_HILITE
;
3170 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3171 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3173 UserReleaseDC(pWnd
, Dc
, FALSE
);
3176 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3178 Item
->xItem
= Rect
.left
;
3179 Item
->yItem
= Rect
.top
;
3180 Item
->cxItem
= Rect
.right
; // Do this for now......
3181 Item
->cyItem
= Rect
.bottom
;
3183 Item
->fState
|= MF_MOUSESELECT
;
3185 if (IS_SYSTEM_MENU(Menu
))
3187 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3189 NC_GetSysPopupPos(pWnd
, &Rect
);
3190 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3191 Rect
.top
= Rect
.bottom
;
3192 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3193 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3197 IntGetWindowRect(pWnd
, &Rect
);
3198 if (Menu
->fFlags
& MNF_POPUP
)
3201 rc
.left
= Item
->xItem
;
3202 rc
.top
= Item
->yItem
;
3203 rc
.right
= Item
->cxItem
; // Do this for now......
3204 rc
.bottom
= Item
->cyItem
;
3206 MENU_AdjustMenuItemRect(Menu
, &rc
);
3208 /* The first item in the popup menu has to be at the
3209 same y position as the focused menu item */
3210 if(Flags
& TPM_LAYOUTRTL
)
3211 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3213 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3214 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3215 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3216 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3217 - UserGetSystemMetrics(SM_CYBORDER
);
3221 if(Flags
& TPM_LAYOUTRTL
)
3222 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3224 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3225 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3226 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3227 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3231 /* use default alignment for submenus */
3232 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3234 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3236 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3237 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3240 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3242 return Item
->spSubMenu
;
3245 /***********************************************************************
3246 * MenuExecFocusedItem
3248 * Execute a menu item (for instance when user pressed Enter).
3249 * Return the wID of the executed item. Otherwise, -1 indicating
3250 * that no menu item was executed, -2 if a popup is shown;
3251 * Have to receive the flags for the TrackPopupMenu options to avoid
3252 * sending unwanted message.
3255 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3259 TRACE("%p menu=%p\n", pmt
, Menu
);
3261 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3266 Item
= &Menu
->rgItems
[Menu
->iItem
];
3268 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3270 if (!(Item
->spSubMenu
))
3272 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3274 /* If TPM_RETURNCMD is set you return the id, but
3275 do not send a message to the owner */
3276 if (!(Flags
& TPM_RETURNCMD
))
3278 if (Menu
->fFlags
& MNF_SYSMENU
)
3280 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3281 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3285 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3287 if (dwStyle
& MNS_NOTIFYBYPOS
)
3288 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3290 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3298 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3305 /***********************************************************************
3306 * MenuSwitchTracking
3308 * Helper function for menu navigation routines.
3310 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3312 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3314 if ( pmt
->TopMenu
!= PtMenu
&&
3315 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3317 /* both are top level menus (system and menu-bar) */
3318 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3319 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3320 pmt
->TopMenu
= PtMenu
;
3324 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3327 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3330 /***********************************************************************
3333 * Return TRUE if we can go on with menu tracking.
3335 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3337 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3343 if (IS_SYSTEM_MENU(PtMenu
))
3345 item
= PtMenu
->rgItems
;
3349 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3354 if (PtMenu
->iItem
!= id
)
3355 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3357 /* If the popup menu is not already "popped" */
3358 if (!(item
->fState
& MF_MOUSESELECT
))
3360 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3365 /* Else the click was on the menu bar, finish the tracking */
3370 /***********************************************************************
3373 * Return the value of MenuExecFocusedItem if
3374 * the selected item was not a popup. Else open the popup.
3375 * A -1 return value indicates that we go on with menu tracking.
3378 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3380 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3387 if ( IS_SYSTEM_MENU(PtMenu
) )
3389 item
= PtMenu
->rgItems
;
3393 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3396 if (item
&& ( PtMenu
->iItem
== Id
))
3398 if (!(item
->spSubMenu
))
3400 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3401 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3402 return ExecutedMenuId
;
3405 /* If we are dealing with the menu bar */
3406 /* and this is a click on an already "popped" item: */
3407 /* Stop the menu tracking and close the opened submenus */
3408 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3413 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3415 PtMenu
->TimeToHide
= TRUE
;
3421 /***********************************************************************
3424 * Walks menu chain trying to find a menu pt maps to.
3426 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3431 if (!menu
) return NULL
;
3433 /* try subpopup first (if any) */
3434 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3436 pItem
= menu
->rgItems
;
3437 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3438 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3440 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3444 /* check the current window (avoiding WM_HITTEST) */
3447 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3448 INT ht
= GetNCHitEx(pWnd
, pt
);
3449 if ( menu
->fFlags
& MNF_POPUP
)
3451 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3453 else if (ht
== HTSYSMENU
)
3454 ret
= get_win_sys_menu(menu
->hWnd
);
3455 else if (ht
== HTMENU
)
3456 ret
= IntGetMenu( menu
->hWnd
);
3461 /***********************************************************************
3464 * Return TRUE if we can go on with menu tracking.
3466 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3468 UINT Index
= NO_SELECTED_ITEM
;
3472 if (IS_SYSTEM_MENU(PtMenu
))
3475 //// ReactOS only HACK: CORE-2338
3476 // Windows tracks mouse moves to the system menu but does not open it.
3477 // Only keyboard tracking can do that.
3479 TRACE("SystemMenu\n");
3480 return TRUE
; // Stay inside the Loop!
3483 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3486 if (Index
== NO_SELECTED_ITEM
)
3488 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3490 else if (PtMenu
->iItem
!= Index
)
3492 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3493 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3498 /***********************************************************************
3501 * Return the handle of the selected sub-popup menu (if any).
3503 static PMENU
MENU_GetSubPopup( PMENU menu
)
3507 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3509 item
= &menu
->rgItems
[menu
->iItem
];
3510 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3512 return item
->spSubMenu
;
3517 /***********************************************************************
3520 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3522 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3526 /* When skipping left, we need to do something special after the
3528 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3532 /* When skipping right, for the non-system menu, we need to
3533 handle the last non-special menu item (ie skip any window
3534 icons such as MDI maximize, restore or close) */
3535 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3537 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3538 while (i
< pmt
->TopMenu
->cItems
) {
3539 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3540 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3544 if (i
== pmt
->TopMenu
->cItems
) {
3548 /* When skipping right, we need to cater for the system menu */
3549 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3551 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3558 MDINEXTMENU NextMenu
;
3565 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3566 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3567 NextMenu
.hmenuNext
= NULL
;
3568 NextMenu
.hwndNext
= NULL
;
3569 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3571 TRACE("%p [%p] -> %p [%p]\n",
3572 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3574 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3576 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3577 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3579 /* switch to the menu bar */
3581 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3585 Id
= MenuTmp
->cItems
- 1;
3587 /* Skip backwards over any system predefined icons,
3588 eg. MDI close, restore etc icons */
3590 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3591 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3594 hNewMenu
= UserHMGetHandle(MenuTmp
);
3596 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3598 /* switch to the system menu */
3599 MenuTmp
= get_win_sys_menu(hNewWnd
);
3600 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3605 else /* application returned a new menu to switch to */
3607 hNewMenu
= NextMenu
.hmenuNext
;
3608 hNewWnd
= NextMenu
.hwndNext
;
3610 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3612 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3614 /* get the real system menu */
3615 MenuTmp
= get_win_sys_menu(hNewWnd
);
3616 hNewMenu
= UserHMGetHandle(MenuTmp
);
3618 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3620 /* FIXME: Not sure what to do here;
3621 * perhaps try to track NewMenu as a popup? */
3623 WARN(" -- got confused.\n");
3630 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3632 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3634 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3635 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3638 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3640 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3641 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3642 ///// Use thread pms!!!!
3643 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3644 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3645 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3646 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3649 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3650 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3657 /***********************************************************************
3660 * The idea is not to show the popup if the next input message is
3661 * going to hide it anyway.
3663 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3667 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3669 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3670 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3675 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3676 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3678 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3679 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3680 if( msg
.message
== WM_KEYDOWN
&&
3681 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3683 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3689 /* failures go through this */
3690 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3694 /***********************************************************************
3697 * Handle a VK_ESCAPE key event in a menu.
3699 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3701 BOOL EndMenu
= TRUE
;
3703 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3705 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3707 PMENU MenuPrev
, MenuTmp
;
3709 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3711 /* close topmost popup */
3712 while (MenuTmp
!= pmt
->CurrentMenu
)
3715 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3718 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3719 pmt
->CurrentMenu
= MenuPrev
;
3727 /***********************************************************************
3730 * Handle a VK_LEFT key event in a menu.
3732 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
, UINT msg
)
3734 PMENU MenuTmp
, MenuPrev
;
3737 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3739 /* Try to move 1 column left (if possible) */
3740 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3742 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3746 /* close topmost popup */
3747 while (MenuTmp
!= pmt
->CurrentMenu
)
3750 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3753 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3754 pmt
->CurrentMenu
= MenuPrev
;
3756 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3758 /* move menu bar selection if no more popups are left */
3760 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3761 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3763 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3765 /* A sublevel menu was displayed - display the next one
3766 * unless there is another displacement coming up */
3768 if (!MENU_SuspendPopup(pmt
, msg
))
3769 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3775 /***********************************************************************
3778 * Handle a VK_RIGHT key event in a menu.
3780 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
, UINT msg
)
3785 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3786 pmt
->CurrentMenu
, pmt
->TopMenu
);
3788 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3790 /* If already displaying a popup, try to display sub-popup */
3792 menutmp
= pmt
->CurrentMenu
;
3793 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3795 /* if subpopup was displayed then we are done */
3796 if (menutmp
!= pmt
->CurrentMenu
) return;
3799 /* Check to see if there's another column */
3800 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3802 TRACE("Going to %d.\n", NextCol
);
3803 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3807 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3809 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3811 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3812 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3819 /* try to move to the next item */
3820 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3821 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3823 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3825 if ( !MENU_SuspendPopup(pmt
, msg
) )
3826 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3831 /***********************************************************************
3834 * Menu tracking code.
3836 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3837 PWND pwnd
, const RECT
*lprect
)
3841 INT executedMenuId
= -1;
3845 BOOL enterIdleSent
= FALSE
;
3846 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3848 if (pti
!= pwnd
->head
.pti
)
3850 ERR("Not the same PTI!!!!\n");
3854 mt
.CurrentMenu
= pmenu
;
3860 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3861 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3862 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3864 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3866 if (wFlags
& TPM_BUTTONDOWN
)
3868 /* Get the result in order to start the tracking or not */
3869 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3870 fInsideMenuLoop
= fRemove
;
3873 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3875 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3877 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3878 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3879 co_UserSetCapture(NULL
); /* release the capture */
3883 capture_win
= IntGetCapture();
3885 while (fInsideMenuLoop
)
3887 BOOL ErrorExit
= FALSE
;
3888 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3891 /* we have to keep the message in the queue until it's
3892 * clear that menu loop is not over yet. */
3896 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3898 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3899 /* remove the message from the queue */
3900 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3904 /* ReactOS Checks */
3905 if (!VerifyWnd(mt
.OwnerWnd
) ||
3906 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3907 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3908 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3910 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3916 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3917 enterIdleSent
= TRUE
;
3918 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3920 co_IntWaitMessage(NULL
, 0, 0);
3924 if (ErrorExit
) break; // Gracefully dropout.
3926 /* check if EndMenu() tried to cancel us, by posting this message */
3927 if (msg
.message
== WM_CANCELMODE
)
3929 /* we are now out of the loop */
3930 fInsideMenuLoop
= FALSE
;
3932 /* remove the message from the queue */
3933 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3935 /* break out of internal loop, ala ESCAPE */
3939 IntTranslateKbdMessage(&msg
, 0);
3942 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3943 enterIdleSent
=FALSE
;
3946 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3949 * Use the mouse coordinates in lParam instead of those in the MSG
3950 * struct to properly handle synthetic messages. They are already
3951 * in screen coordinates.
3953 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3954 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3956 /* Find a menu for this mouse event */
3957 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3961 /* no WM_NC... messages in captured state */
3963 case WM_RBUTTONDBLCLK
:
3964 case WM_RBUTTONDOWN
:
3965 if (!(wFlags
& TPM_RIGHTBUTTON
))
3967 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3971 case WM_LBUTTONDBLCLK
:
3972 case WM_LBUTTONDOWN
:
3973 /* If the message belongs to the menu, removes it from the queue */
3974 /* Else, end menu tracking */
3975 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3976 fInsideMenuLoop
= fRemove
;
3977 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3978 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3982 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3985 /* Check if a menu was selected by the mouse */
3988 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
3990 /* End the loop if executedMenuId is an item ID */
3991 /* or if the job was done (executedMenuId = 0). */
3992 fRemove
= (executedMenuId
!= -1);
3993 fInsideMenuLoop
= !fRemove
;
3995 /* No menu was selected by the mouse */
3996 /* if the function was called by TrackPopupMenu, continue
3997 with the menu tracking. If not, stop it */
3999 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4004 /* the selected menu item must be changed every time */
4005 /* the mouse moves. */
4008 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4010 } /* switch(msg.message) - mouse */
4012 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4014 fRemove
= TRUE
; /* Keyboard messages are always removed */
4023 fInsideMenuLoop
= FALSE
;
4028 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4029 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4033 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4034 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4035 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4036 else /* otherwise try to move selection */
4037 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4041 MENU_KeyLeft( &mt
, wFlags
, msg
.message
);
4045 MENU_KeyRight( &mt
, wFlags
, msg
.message
);
4049 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4055 hi
.cbSize
= sizeof(HELPINFO
);
4056 hi
.iContextType
= HELPINFO_MENUITEM
;
4057 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4060 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4061 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4062 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4063 hi
.MousePos
= msg
.pt
;
4064 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4071 break; /* WM_KEYDOWN */
4079 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4081 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4082 fEndMenu
= (executedMenuId
!= -2);
4083 fInsideMenuLoop
= !fEndMenu
;
4087 /* Hack to avoid control chars. */
4088 /* We will find a better way real soon... */
4089 if (msg
.wParam
< 32) break;
4091 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4093 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4094 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4097 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4098 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4099 fEndMenu
= (executedMenuId
!= -2);
4100 fInsideMenuLoop
= !fEndMenu
;
4104 } /* switch(msg.message) - kbd */
4108 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4109 IntDispatchMessage( &msg
);
4113 if (fInsideMenuLoop
) fRemove
= TRUE
;
4115 /* finally remove message from the queue */
4117 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4118 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4119 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4122 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4123 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4124 co_UserSetCapture(NULL
); /* release the capture */
4126 /* If dropdown is still painted and the close box is clicked on
4127 then the menu will be destroyed as part of the DispatchMessage above.
4128 This will then invalidate the menu handle in mt.hTopMenu. We should
4129 check for this first. */
4130 if ( VerifyMenu( mt
.TopMenu
) )
4132 if (VerifyWnd(mt
.OwnerWnd
))
4134 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4136 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4138 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4141 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4143 co_UserDestroyWindow(pwndTM
);
4145 mt
.TopMenu
->hWnd
= NULL
;
4147 if (!(wFlags
& TPM_NONOTIFY
))
4149 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4150 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4153 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4154 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4157 /* Reset the variable for hiding menu */
4158 mt
.TopMenu
->TimeToHide
= FALSE
;
4161 /* The return value is only used by TrackPopupMenu */
4162 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4163 if (executedMenuId
== -1) executedMenuId
= 0;
4164 return executedMenuId
;
4167 /***********************************************************************
4170 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4173 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4175 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4177 co_UserHideCaret(0);
4179 /* This makes the menus of applications built with Delphi work.
4180 * It also enables menus to be displayed in more than one window,
4181 * but there are some bugs left that need to be fixed in this case.
4185 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4189 top_popup
= Menu
->hWnd
;
4190 top_popup_hmenu
= UserHMGetHandle(Menu
);
4193 fInsideMenuLoop
= TRUE
;
4196 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4197 if (!(wFlags
& TPM_NONOTIFY
))
4199 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4203 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4205 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4206 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4207 co_UserSetCapture(capture_win
); // 2
4208 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4210 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4212 if (!(wFlags
& TPM_NONOTIFY
))
4214 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4215 /* If an app changed/recreated menu bar entries in WM_INITMENU
4216 * menu sizes will be recalculated once the menu created/shown.
4220 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4222 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4227 /***********************************************************************
4230 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4232 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4234 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4236 if (!(wFlags
& TPM_NONOTIFY
))
4237 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4239 co_UserShowCaret(0);
4242 top_popup_hmenu
= NULL
;
4247 /***********************************************************************
4248 * MenuTrackMouseMenuBar
4250 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4252 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4254 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) );
4255 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4257 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4259 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4260 if (VerifyMenu(pMenu
))
4262 /* map point to parent client coordinates */
4263 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4264 if (Parent
!= UserGetDesktopWindow())
4266 IntScreenToClient(Parent
, &pt
);
4269 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4270 /* fetch the window menu again, it may have changed */
4271 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4272 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4273 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4277 /***********************************************************************
4278 * MenuTrackKbdMenuBar
4280 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4282 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4284 UINT uItem
= NO_SELECTED_ITEM
;
4286 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4288 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4290 /* find window that has a menu */
4292 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4293 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4295 /* check if we have to track a system menu */
4297 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4298 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4300 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4301 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4303 wParam
|= HTSYSMENU
; /* prevent item lookup */
4306 if (!VerifyMenu( TrackMenu
)) return;
4308 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4310 /* fetch the window menu again, it may have changed */
4311 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4313 if( wChar
&& wChar
!= ' ' )
4315 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4316 if ( uItem
>= (UINT
)(-2) )
4318 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4319 /* schedule end of menu tracking */
4320 wFlags
|= TF_ENDMENU
;
4325 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4327 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4329 if( uItem
== NO_SELECTED_ITEM
)
4330 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4332 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4336 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4337 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4340 /**********************************************************************
4341 * TrackPopupMenuEx (USER32.@)
4343 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4344 PWND pWnd
, LPTPMPARAMS lpTpm
)
4347 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4349 if (pti
!= pWnd
->head
.pti
)
4351 ERR("Must be the same pti!\n");
4355 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4356 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4357 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4359 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4361 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4365 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4367 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4369 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4370 if (!(wFlags
& TPM_NONOTIFY
))
4372 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4375 if (menu
->fFlags
& MNF_SYSMENU
)
4376 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4378 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4379 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4380 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4383 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4384 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4385 co_UserSetCapture(NULL
); /* release the capture */
4389 // HACK : Until back trace fault in co_IntUpdateWindows and MENU_TrackMenu.
4391 if (EngGetLastError() == ERROR_ACCESS_DENIED
)
4393 EngSetLastError(NO_ERROR
);
4396 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4400 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4401 if (pwndM
) // wine hack around this with their destroy function.
4402 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4405 if (!(wFlags
& TPM_NONOTIFY
))
4407 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4408 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4426 PPOPUPMENU pPopupMenu
;
4430 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4436 if (Message
!= WM_NCCREATE
)
4438 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4441 Wnd
->fnid
= FNID_MENU
;
4442 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4443 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4444 pPopupMenu
->spwndPopupMenu
= Wnd
;
4445 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4446 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4452 if (Wnd
->fnid
!= FNID_MENU
)
4454 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4457 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4465 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4466 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4470 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4471 *lResult
= MA_NOACTIVATE
;
4477 IntBeginPaint(Wnd
, &ps
);
4478 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4479 IntEndPaint(Wnd
, &ps
);
4483 case WM_PRINTCLIENT
:
4485 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4494 /* zero out global pointer in case resident popup window was destroyed. */
4497 if (UserHMGetHandle(Wnd
) == top_popup
)
4500 top_popup_hmenu
= NULL
;
4505 ERR("No Window Pop Up!\n");
4511 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4512 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4513 Wnd
->fnid
= FNID_DESTROY
;
4517 case MM_SETMENUHANDLE
: // wine'isms
4520 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4523 ERR("Bad Menu Handle\n");
4526 pPopupMenu
->spmenu
= pmenu
;
4530 case MM_GETMENUHANDLE
: // wine'isms
4532 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4536 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4538 ERR("Someone is passing unknown menu messages %d\n",Message
);
4540 TRACE("PMWP to IDWP %d\n",Message
);
4541 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4549 IntHiliteMenuItem(PWND WindowObject
,
4555 UINT uItem
= uItemHilite
;
4557 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4559 if (uHilite
& MF_HILITE
)
4561 MenuItem
->fState
|= MF_HILITE
;
4565 MenuItem
->fState
&= ~MF_HILITE
;
4567 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4568 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4569 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4571 return TRUE
; // Always returns true!!!!
4575 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4579 DWORD dwExStyle
= 0;
4580 BOOLEAN retValue
= TRUE
;
4582 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4584 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4586 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4588 dwStyle
= pWindowObject
->style
;
4589 dwExStyle
= pWindowObject
->ExStyle
;
4591 bti
->rcTitleBar
.top
= 0;
4592 bti
->rcTitleBar
.left
= 0;
4593 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4594 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4596 /* Is it iconiced ? */
4597 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4599 /* Remove frame from rectangle */
4600 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4602 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4603 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4605 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4607 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4608 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4610 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4612 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4613 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4616 /* We have additional border information if the window
4617 * is a child (but not an MDI child) */
4618 if ( (dwStyle
& WS_CHILD
) &&
4619 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4621 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4623 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4624 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4627 if (dwExStyle
& WS_EX_STATICEDGE
)
4629 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4630 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4635 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4636 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4637 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4639 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4640 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4642 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4643 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4647 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4648 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4649 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4652 if (dwStyle
& WS_CAPTION
)
4654 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4655 if (dwStyle
& WS_SYSMENU
)
4657 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4659 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4660 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4664 if (!(dwStyle
& WS_MINIMIZEBOX
))
4666 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4668 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4670 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4674 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4676 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4678 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4680 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4685 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4686 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4687 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4688 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4693 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4698 EngSetLastError(ERROR_INVALID_PARAMETER
);
4710 LPCMENUITEMINFOW UnsafeItemInfo
,
4711 PUNICODE_STRING lpstr
)
4714 ROSMENUITEMINFO ItemInfo
;
4716 /* Try to copy the whole MENUITEMINFOW structure */
4717 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4718 if (NT_SUCCESS(Status
))
4720 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4721 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4723 EngSetLastError(ERROR_INVALID_PARAMETER
);
4726 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4729 /* Try to copy without last field (not present in older versions) */
4730 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4731 if (NT_SUCCESS(Status
))
4733 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4735 EngSetLastError(ERROR_INVALID_PARAMETER
);
4738 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4739 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4742 SetLastNtError(Status
);
4746 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4751 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4756 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4758 if (pItem
->spSubMenu
)
4760 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4763 return (pItem
->fType
| pItem
->fState
);
4766 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4771 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4776 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4778 if (pItem
->spSubMenu
)
4780 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4786 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4788 PMENU menu
, pSubTarget
;
4790 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4791 return NO_SELECTED_ITEM
;
4793 pSubTarget
= UserGetMenuObject(hSubTarget
);
4795 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4797 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4803 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4805 PWINSTATION_OBJECT WinStaObject
;
4809 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4811 if (gpepCSRSS
!= CurrentProcess
)
4814 * gpepCSRSS does not have a Win32WindowStation
4817 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4823 if (!NT_SUCCESS(Status
))
4825 ERR("Validation of window station handle (%p) failed\n",
4826 CurrentProcess
->Win32WindowStation
);
4827 SetLastNtError(Status
);
4830 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4831 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4833 ERR("Desktop Window Station does not match Process one!\n");
4835 ObDereferenceObject(WinStaObject
);
4839 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4842 if (Menu
) UserDereferenceObject(Menu
);
4843 return (HMENU
)Handle
;
4851 PROSMENUITEMINFO ItemInfo
,
4853 PUNICODE_STRING lpstr
)
4858 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4860 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4865 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4869 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4879 PROSMENUITEMINFO UnsafeItemInfo
,
4881 PUNICODE_STRING lpstr
)
4884 ROSMENUITEMINFO ItemInfo
;
4889 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4890 if (! NT_SUCCESS(Status
))
4892 SetLastNtError(Status
);
4895 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4896 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4897 Size
!= sizeof(ROSMENUITEMINFO
) )
4899 EngSetLastError(ERROR_INVALID_PARAMETER
);
4902 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4903 if (! NT_SUCCESS(Status
))
4905 SetLastNtError(Status
);
4908 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4910 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4911 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4913 EngSetLastError(ERROR_INVALID_PARAMETER
);
4917 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4919 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4920 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4923 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4929 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4933 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4936 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4937 if (! NT_SUCCESS(Status
))
4939 SetLastNtError(Status
);
4951 PROSMENUINFO UnsafeMenuInfo
,
4957 ROSMENUINFO MenuInfo
;
4959 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4960 if (! NT_SUCCESS(Status
))
4962 SetLastNtError(Status
);
4965 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4967 EngSetLastError(ERROR_INVALID_PARAMETER
);
4970 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4971 if (! NT_SUCCESS(Status
))
4973 SetLastNtError(Status
);
4980 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4985 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4988 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
4989 if (! NT_SUCCESS(Status
))
4991 SetLastNtError(Status
);
5011 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5013 Rect
->left
= MenuItem
->xItem
;
5014 Rect
->top
= MenuItem
->yItem
;
5015 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5016 Rect
->bottom
= MenuItem
->cyItem
;
5020 ERR("Failed Item Lookup! %u\n", uItem
);
5026 HWND hWnd
= Menu
->hWnd
;
5027 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5030 if (Menu
->fFlags
& MNF_POPUP
)
5032 XMove
= pWnd
->rcClient
.left
;
5033 YMove
= pWnd
->rcClient
.top
;
5037 XMove
= pWnd
->rcWindow
.left
;
5038 YMove
= pWnd
->rcWindow
.top
;
5041 Rect
->left
+= XMove
;
5043 Rect
->right
+= XMove
;
5044 Rect
->bottom
+= YMove
;
5049 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5051 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5052 HMENU hSysMenu
, hNewMenu
= NULL
;
5053 ROSMENUITEMINFO ItemInfoSet
= {0};
5054 ROSMENUITEMINFO ItemInfo
= {0};
5055 UNICODE_STRING MenuName
;
5057 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5058 if (NULL
== hSysMenu
)
5062 SysMenu
= UserGetMenuObject(hSysMenu
);
5063 if (NULL
== SysMenu
)
5065 UserDestroyMenu(hSysMenu
);
5069 SysMenu
->fFlags
|= MNF_SYSMENU
;
5070 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5074 //hNewMenu = co_IntLoadSysMenuTemplate();
5075 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5077 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5078 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5082 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5083 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5084 //ERR("%wZ\n",&MenuName);
5089 IntReleaseMenuObject(SysMenu
);
5090 UserDestroyMenu(hSysMenu
);
5093 Menu
= UserGetMenuObject(hNewMenu
);
5096 IntReleaseMenuObject(SysMenu
);
5097 UserDestroyMenu(hSysMenu
);
5101 // Do the rest in here.
5103 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5105 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5106 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5107 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5108 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5109 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5110 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5111 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5112 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5113 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5114 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5116 NewMenu
= IntCloneMenu(Menu
);
5118 IntReleaseMenuObject(NewMenu
);
5119 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5121 IntDestroyMenuObject(Menu
, FALSE
);
5129 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5131 if (Window
->pcls
->style
& CS_NOCLOSE
)
5132 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5134 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5135 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5136 ItemInfo
.fType
= MF_POPUP
;
5137 ItemInfo
.fState
= MFS_ENABLED
;
5138 ItemInfo
.dwTypeData
= NULL
;
5140 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5141 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5145 ERR("failed to load system menu!\n");
5150 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5156 if (Window
->SystemMenu
)
5158 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5159 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5161 IntDestroyMenuObject(Menu
, TRUE
);
5162 Window
->SystemMenu
= NULL
;
5168 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5169 if ((!Window
->SystemMenu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5171 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5172 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5176 if (Window
->SystemMenu
)
5178 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5179 /* Store the dummy sysmenu handle to facilitate the refresh */
5180 /* of the close button if the SC_CLOSE item change */
5181 Menu
= UserGetMenuObject(hMenu
);
5184 Menu
->spwndNotify
= Window
;
5185 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5193 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5197 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5199 if (Window
->SystemMenu
)
5201 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5204 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5205 IntDestroyMenuObject(OldMenu
, TRUE
);
5209 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5211 { // Use spmenuSys too!
5212 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5215 Window
->SystemMenu
= NULL
;
5217 if (Menu
&& Window
!= Menu
->spwndNotify
)
5219 Menu
->spwndNotify
= Window
;
5231 PMENU OldMenu
, NewMenu
= NULL
;
5233 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5235 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5236 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5240 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5248 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5249 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5258 NewMenu
= IntGetMenuObject(Menu
);
5259 if (NULL
== NewMenu
)
5261 if (NULL
!= OldMenu
)
5263 IntReleaseMenuObject(OldMenu
);
5265 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5268 if (NULL
!= NewMenu
->hWnd
)
5270 /* Can't use the same menu for two windows */
5271 if (NULL
!= OldMenu
)
5273 IntReleaseMenuObject(OldMenu
);
5275 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5281 Wnd
->IDMenu
= (UINT
) Menu
;
5282 if (NULL
!= NewMenu
)
5284 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5285 IntReleaseMenuObject(NewMenu
);
5287 if (NULL
!= OldMenu
)
5289 OldMenu
->hWnd
= NULL
;
5290 IntReleaseMenuObject(OldMenu
);
5297 /* FUNCTIONS *****************************************************************/
5302 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5317 UserEnterExclusive();
5319 if(!(Window
= UserGetWindowObject(hwnd
)))
5321 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5326 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5333 Rect
.left
= leftBorder
;
5334 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5338 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5340 UserReleaseDC( 0, hdc
, FALSE
);
5351 NtUserCheckMenuItem(
5357 DECLARE_RETURN(DWORD
);
5359 TRACE("Enter NtUserCheckMenuItem\n");
5360 UserEnterExclusive();
5362 if(!(Menu
= UserGetMenuObject(hMenu
)))
5367 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5370 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5385 DECLARE_RETURN(BOOL
);
5387 TRACE("Enter NtUserDeleteMenu\n");
5388 UserEnterExclusive();
5390 if(!(Menu
= UserGetMenuObject(hMenu
)))
5395 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5398 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5404 * NtUserGetSystemMenu
5406 * The NtUserGetSystemMenu function allows the application to access the
5407 * window menu (also known as the system menu or the control menu) for
5408 * copying and modifying.
5412 * Handle to the window that will own a copy of the window menu.
5414 * Specifies the action to be taken. If this parameter is FALSE,
5415 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5416 * currently in use. The copy is initially identical to the window menu
5417 * but it can be modified.
5418 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5419 * to the default state. The previous window menu, if any, is destroyed.
5422 * If the bRevert parameter is FALSE, the return value is a handle to a
5423 * copy of the window menu. If the bRevert parameter is TRUE, the return
5431 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5435 DECLARE_RETURN(HMENU
);
5437 TRACE("Enter NtUserGetSystemMenu\n");
5440 if (!(Window
= UserGetWindowObject(hWnd
)))
5445 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5450 RETURN(Menu
->head
.h
);
5453 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5459 * NtUserSetSystemMenu
5466 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5468 BOOL Result
= FALSE
;
5471 DECLARE_RETURN(BOOL
);
5473 TRACE("Enter NtUserSetSystemMenu\n");
5474 UserEnterExclusive();
5476 if (!(Window
= UserGetWindowObject(hWnd
)))
5484 * Assign new menu handle and Up the Lock Count.
5486 if (!(Menu
= IntGetMenuObject(hMenu
)))
5491 Result
= IntSetSystemMenu(Window
, Menu
);
5494 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5499 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5508 NtUserGetTitleBarInfo(
5513 TITLEBARINFO bartitleinfo
;
5514 DECLARE_RETURN(BOOLEAN
);
5515 BOOLEAN retValue
= TRUE
;
5517 TRACE("Enter NtUserGetTitleBarInfo\n");
5518 UserEnterExclusive();
5520 /* Vaildate the windows handle */
5521 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5523 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5529 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5530 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5531 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5533 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5535 /* Fail copy the data */
5536 EngSetLastError(ERROR_INVALID_PARAMETER
);
5541 /* Get the tile bar info */
5544 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5549 /* Copy our buffer to user mode buffer bti */
5550 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5551 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5555 /* Fail copy the data */
5556 EngSetLastError(ERROR_INVALID_PARAMETER
);
5566 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5574 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5577 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5579 if(!(Menu
= UserGetMenuObject(hMenu
)))
5584 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5586 EngSetLastError(ERROR_ACCESS_DENIED
);
5589 return IntDestroyMenuObject(Menu
, FALSE
);
5600 DECLARE_RETURN(BOOL
);
5602 TRACE("Enter NtUserDestroyMenu\n");
5603 UserEnterExclusive();
5605 if(!(Menu
= UserGetMenuObject(hMenu
)))
5609 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5611 EngSetLastError(ERROR_ACCESS_DENIED
);
5614 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5617 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5626 NtUserEnableMenuItem(
5632 DECLARE_RETURN(UINT
);
5634 TRACE("Enter NtUserEnableMenuItem\n");
5635 UserEnterExclusive();
5637 if(!(Menu
= UserGetMenuObject(hMenu
)))
5642 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5645 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5657 TRACE("Enter NtUserEndMenu\n");
5658 UserEnterExclusive();
5659 /* if ( gptiCurrent->pMenuState &&
5660 gptiCurrent->pMenuState->pGlobalPopupMenu )
5662 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5665 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5668 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5670 if (fInsideMenuLoop
&& top_popup
)
5672 fInsideMenuLoop
= FALSE
;
5673 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5676 TRACE("Leave NtUserEndMenu\n");
5684 NtUserGetMenuBarInfo(
5694 PPOPUPMENU pPopupMenu
;
5695 USER_REFERENCE_ENTRY Ref
;
5696 NTSTATUS Status
= STATUS_SUCCESS
;
5698 DECLARE_RETURN(BOOL
);
5700 TRACE("Enter NtUserGetMenuBarInfo\n");
5703 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5705 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5709 UserRefObjectCo(pWnd
, &Ref
);
5711 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5713 kmbi
.hwndMenu
= NULL
;
5714 kmbi
.fBarFocused
= FALSE
;
5715 kmbi
.fFocused
= FALSE
;
5720 if (!pWnd
->pcls
->fnid
)
5722 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5724 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5725 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5728 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5729 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5730 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5731 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5733 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5735 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5740 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5741 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5742 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5745 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5746 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5747 hMenu
= UserHMGetHandle(Menu
);
5758 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5759 kmbi
.cbSize
= pmbi
->cbSize
;
5761 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5767 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5769 EngSetLastError(ERROR_INVALID_PARAMETER
);
5773 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5777 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5782 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5783 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5784 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5785 TRACE("idItem a 0 %d\n",Ret
);
5789 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5790 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5794 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5795 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5798 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5799 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5801 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5806 kmbi
.fFocused
= kmbi
.fBarFocused
;
5811 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5812 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5816 Status
= _SEH2_GetExceptionCode();
5820 if (!NT_SUCCESS(Status
))
5822 SetLastNtError(Status
);
5829 if (pWnd
) UserDerefObjectCo(pWnd
);
5830 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5843 PMENU Menu
, SubMenu
;
5846 DECLARE_RETURN(UINT
);
5848 TRACE("Enter NtUserGetMenuIndex\n");
5851 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5852 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5855 MenuItem
= Menu
->rgItems
;
5856 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5858 if (MenuItem
->spSubMenu
== SubMenu
)
5859 RETURN(MenuItem
->wID
);
5864 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5873 NtUserGetMenuItemRect(
5884 NTSTATUS Status
= STATUS_SUCCESS
;
5885 DECLARE_RETURN(BOOL
);
5887 TRACE("Enter NtUserGetMenuItemRect\n");
5890 if (!(Menu
= UserGetMenuObject(hMenu
)))
5895 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5897 Rect
.left
= MenuItem
->xItem
;
5898 Rect
.top
= MenuItem
->yItem
;
5899 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5900 Rect
.bottom
= MenuItem
->cyItem
;
5910 if (lprcItem
== NULL
) RETURN( FALSE
);
5912 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5914 if (Menu
->fFlags
& MNF_POPUP
)
5916 XMove
= ReferenceWnd
->rcClient
.left
;
5917 YMove
= ReferenceWnd
->rcClient
.top
;
5921 XMove
= ReferenceWnd
->rcWindow
.left
;
5922 YMove
= ReferenceWnd
->rcWindow
.top
;
5927 Rect
.right
+= XMove
;
5928 Rect
.bottom
+= YMove
;
5932 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5934 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5936 Status
= _SEH2_GetExceptionCode();
5940 if (!NT_SUCCESS(Status
))
5942 SetLastNtError(Status
);
5948 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5957 NtUserHiliteMenuItem(
5965 DECLARE_RETURN(BOOLEAN
);
5967 TRACE("Enter NtUserHiliteMenuItem\n");
5968 UserEnterExclusive();
5970 if(!(Window
= UserGetWindowObject(hWnd
)))
5972 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5976 if(!(Menu
= UserGetMenuObject(hMenu
)))
5978 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5982 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
5985 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
5995 NtUserDrawMenuBarTemp(
6005 NTSTATUS Status
= STATUS_SUCCESS
;
6006 DECLARE_RETURN(DWORD
);
6008 ERR("Enter NtUserDrawMenuBarTemp\n");
6009 UserEnterExclusive();
6011 if(!(Window
= UserGetWindowObject(hWnd
)))
6013 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6017 if(!(Menu
= UserGetMenuObject(hMenu
)))
6019 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6025 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6026 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6028 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6030 Status
= _SEH2_GetExceptionCode();
6034 if (Status
!= STATUS_SUCCESS
)
6036 SetLastNtError(Status
);
6040 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6043 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6052 NtUserMenuItemFromPoint(
6062 DECLARE_RETURN(int);
6064 TRACE("Enter NtUserMenuItemFromPoint\n");
6065 UserEnterExclusive();
6067 if (!(Menu
= UserGetMenuObject(hMenu
)))
6072 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6077 X
-= Window
->rcWindow
.left
;
6078 Y
-= Window
->rcWindow
.top
;
6081 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6085 Rect
.left
= mi
->xItem
;
6086 Rect
.top
= mi
->yItem
;
6087 Rect
.right
= mi
->cxItem
;
6088 Rect
.bottom
= mi
->cyItem
;
6090 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6092 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6098 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6101 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6121 UserEnterExclusive();
6123 if(!(Window
= UserGetWindowObject(hWnd
)))
6125 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6130 Rect
.left
= leftBorder
;
6131 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6135 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6152 DECLARE_RETURN(BOOL
);
6154 TRACE("Enter NtUserRemoveMenu\n");
6155 UserEnterExclusive();
6157 if(!(Menu
= UserGetMenuObject(hMenu
)))
6162 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6165 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6182 DECLARE_RETURN(BOOL
);
6184 TRACE("Enter NtUserSetMenu\n");
6185 UserEnterExclusive();
6187 if (!(Window
= UserGetWindowObject(hWnd
)))
6192 if (!IntSetMenu(Window
, Menu
, &Changed
))
6197 // Not minimized and please repaint!!!
6198 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6200 USER_REFERENCE_ENTRY Ref
;
6201 UserRefObjectCo(Window
, &Ref
);
6202 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6203 UserDerefObjectCo(Window
);
6209 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6218 NtUserSetMenuContextHelpId(
6220 DWORD dwContextHelpId
)
6223 DECLARE_RETURN(BOOL
);
6225 TRACE("Enter NtUserSetMenuContextHelpId\n");
6226 UserEnterExclusive();
6228 if(!(Menu
= UserGetMenuObject(hMenu
)))
6233 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6236 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6245 NtUserSetMenuDefaultItem(
6251 DECLARE_RETURN(BOOL
);
6253 TRACE("Enter NtUserSetMenuDefaultItem\n");
6254 UserEnterExclusive();
6256 if(!(Menu
= UserGetMenuObject(hMenu
)))
6261 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6264 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6273 NtUserSetMenuFlagRtoL(
6277 DECLARE_RETURN(BOOL
);
6279 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6280 UserEnterExclusive();
6282 if(!(Menu
= UserGetMenuObject(hMenu
)))
6287 RETURN(IntSetMenuFlagRtoL(Menu
));
6290 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6299 NtUserThunkedMenuInfo(
6304 DECLARE_RETURN(BOOL
);
6306 TRACE("Enter NtUserThunkedMenuInfo\n");
6307 UserEnterExclusive();
6309 if (!(Menu
= UserGetMenuObject(hMenu
)))
6314 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6317 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6326 NtUserThunkedMenuItemInfo(
6331 LPMENUITEMINFOW lpmii
,
6332 PUNICODE_STRING lpszCaption
)
6336 UNICODE_STRING lstrCaption
;
6337 DECLARE_RETURN(BOOL
);
6339 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6340 UserEnterExclusive();
6342 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6343 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6345 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6347 if (!(Menu
= UserGetMenuObject(hMenu
)))
6352 /* Check if we got a Caption */
6353 if (lpszCaption
&& lpszCaption
->Buffer
)
6355 /* Copy the string to kernel mode */
6356 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6359 if (!NT_SUCCESS(Status
))
6361 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6362 SetLastNtError(Status
);
6367 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6369 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6372 if (lstrCaption
.Buffer
)
6374 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6377 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6386 NtUserTrackPopupMenuEx(
6398 USER_REFERENCE_ENTRY Ref
;
6400 TRACE("Enter NtUserTrackPopupMenuEx\n");
6401 UserEnterExclusive();
6402 /* Parameter check */
6403 if (!(menu
= UserGetMenuObject( hMenu
)))
6405 ERR("TPME : Invalid Menu handle.\n");
6406 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6410 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6412 ERR("TPME : Invalid Window handle.\n");
6420 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6425 _SEH2_YIELD(goto Exit
);
6429 UserRefObjectCo(pWnd
, &Ref
);
6430 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6431 UserDerefObjectCo(pWnd
);
6434 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);