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 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
61 #define IS_SYSTEM_POPUP(MenuInfo) \
62 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
64 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
66 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
67 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
69 /* Maximum number of menu items a menu can contain */
70 #define MAX_MENU_ITEMS (0x4000)
71 #define MAX_GOINTOSUBMENU (0x10)
73 /* Space between 2 columns */
74 #define MENU_COL_SPACE 4
76 /* top and bottom margins for popup menus */
77 #define MENU_TOP_MARGIN 2 //3
78 #define MENU_BOTTOM_MARGIN 2
80 #define MENU_ITEM_HBMP_SPACE (5)
81 #define MENU_BAR_ITEMS_SPACE (12)
82 #define SEPARATOR_HEIGHT (5)
83 #define MENU_TAB_SPACE (8)
88 PMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
89 PMENU TopMenu
; /* initial menu */
90 PWND OwnerWnd
; /* where notifications are sent */
94 /* Internal MenuTrackMenu() flags */
95 #define TPM_INTERNAL 0xF0000000
96 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
97 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
102 #define UpdateMenuItemState(state, change) \
104 if((change) & MF_GRAYED) { \
105 (state) |= MF_GRAYED; \
107 (state) &= ~MF_GRAYED; \
108 } /* Separate the two for test_menu_resource_layout.*/ \
109 if((change) & MF_DISABLED) { \
110 (state) |= MF_DISABLED; \
112 (state) &= ~MF_DISABLED; \
114 if((change) & MFS_CHECKED) { \
115 (state) |= MFS_CHECKED; \
117 (state) &= ~MFS_CHECKED; \
119 if((change) & MFS_HILITE) { \
120 (state) |= MFS_HILITE; \
122 (state) &= ~MFS_HILITE; \
124 if((change) & MFS_DEFAULT) { \
125 (state) |= MFS_DEFAULT; \
127 (state) &= ~MFS_DEFAULT; \
129 if((change) & MF_MOUSESELECT) { \
130 (state) |= MF_MOUSESELECT; \
132 (state) &= ~MF_MOUSESELECT; \
138 DumpMenuItemList(PMENU Menu
, PITEM MenuItem
)
140 UINT cnt
= 0, i
= Menu
->cItems
;
143 if(MenuItem
->lpstr
.Length
)
144 DbgPrint(" %d. %wZ\n", ++cnt
, &MenuItem
->lpstr
);
146 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt
, (DWORD
)MenuItem
->lpstr
.Buffer
);
148 if(MFT_BITMAP
& MenuItem
->fType
)
149 DbgPrint("MFT_BITMAP ");
150 if(MFT_MENUBARBREAK
& MenuItem
->fType
)
151 DbgPrint("MFT_MENUBARBREAK ");
152 if(MFT_MENUBREAK
& MenuItem
->fType
)
153 DbgPrint("MFT_MENUBREAK ");
154 if(MFT_OWNERDRAW
& MenuItem
->fType
)
155 DbgPrint("MFT_OWNERDRAW ");
156 if(MFT_RADIOCHECK
& MenuItem
->fType
)
157 DbgPrint("MFT_RADIOCHECK ");
158 if(MFT_RIGHTJUSTIFY
& MenuItem
->fType
)
159 DbgPrint("MFT_RIGHTJUSTIFY ");
160 if(MFT_SEPARATOR
& MenuItem
->fType
)
161 DbgPrint("MFT_SEPARATOR ");
162 if(MFT_STRING
& MenuItem
->fType
)
163 DbgPrint("MFT_STRING ");
164 DbgPrint("\n fState=");
165 if(MFS_DISABLED
& MenuItem
->fState
)
166 DbgPrint("MFS_DISABLED ");
168 DbgPrint("MFS_ENABLED ");
169 if(MFS_CHECKED
& MenuItem
->fState
)
170 DbgPrint("MFS_CHECKED ");
172 DbgPrint("MFS_UNCHECKED ");
173 if(MFS_HILITE
& MenuItem
->fState
)
174 DbgPrint("MFS_HILITE ");
176 DbgPrint("MFS_UNHILITE ");
177 if(MFS_DEFAULT
& MenuItem
->fState
)
178 DbgPrint("MFS_DEFAULT ");
179 if(MFS_GRAYED
& MenuItem
->fState
)
180 DbgPrint("MFS_GRAYED ");
181 DbgPrint("\n wId=%d\n", MenuItem
->wID
);
185 DbgPrint("Entries: %d\n", cnt
);
190 #define FreeMenuText(Menu,MenuItem) \
192 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
193 (MenuItem)->lpstr.Length) { \
194 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
199 IntGetMenuObject(HMENU hMenu
)
201 PMENU Menu
= UserGetMenuObject(hMenu
);
203 Menu
->head
.cLockObj
++;
208 PMENU FASTCALL
VerifyMenu(PMENU pMenu
)
214 if (!pMenu
) return NULL
;
216 Error
= EngGetLastError();
220 hMenu
= UserHMGetHandle(pMenu
);
221 pItem
= pMenu
->rgItems
;
228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
230 ERR("Run away LOOP!\n");
231 EngSetLastError(Error
);
232 _SEH2_YIELD(return NULL
);
236 if ( UserObjectInDestroy(hMenu
))
238 ERR("Menu is marked for destruction!\n");
241 EngSetLastError(Error
);
247 IntIsMenu(HMENU Menu
)
249 if (UserGetMenuObject(Menu
)) return TRUE
;
255 IntGetMenu(HWND hWnd
)
257 PWND Wnd
= ValidateHwndNoErr(hWnd
);
262 return UserGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
265 PMENU
get_win_sys_menu( HWND hwnd
)
268 WND
*win
= ValidateHwndNoErr( hwnd
);
271 ret
= UserGetMenuObject(win
->SystemMenu
);
276 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
)
280 if (pMenu
->rgItems
) /* recursively destroy submenus */
283 ITEM
*item
= pMenu
->rgItems
;
284 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
286 SubMenu
= item
->spSubMenu
;
287 item
->spSubMenu
= NULL
;
289 /* Remove Item Text */
290 FreeMenuText(pMenu
,item
);
292 /* Remove Item Bitmap and set it for this process */
293 if (item
->hbmp
&& !(item
->fState
& MFS_HBMMENUBMP
))
295 GreSetObjectOwner(item
->hbmp
, GDI_OBJ_HMGR_POWNED
);
299 /* Remove Item submenu */
300 if (bRecurse
&& SubMenu
)//VerifyMenu(SubMenu))
302 /* Release submenu since it was referenced when inserted */
303 IntReleaseMenuObject(SubMenu
);
304 IntDestroyMenuObject(SubMenu
, bRecurse
);
308 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
309 pMenu
->rgItems
= NULL
;
315 /* Callback for the object manager */
317 UserDestroyMenuObject(PVOID Object
)
319 return IntDestroyMenuObject(Object
, TRUE
);
323 IntDestroyMenuObject(PMENU Menu
, BOOL bRecurse
)
329 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
334 Window
= ValidateHwndNoErr(Menu
->hWnd
);
337 //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
339 /* DestroyMenu should not destroy system menu popup owner */
340 if ((Menu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
)
342 // Should we check it to see if it has Class?
343 ERR("FIXME Pop up menu window thing'ie\n");
344 //co_UserDestroyWindow( Window );
350 if (!UserMarkObjectDestroy(Menu
)) return TRUE
;
352 /* Remove all menu items */
353 IntDestroyMenu( Menu
, bRecurse
);
355 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
356 TRACE("IntDestroyMenuObject %d\n",ret
);
366 NONCLIENTMETRICSW ncm
;
368 /* get the menu font */
369 if (!ghMenuFont
|| !ghMenuFontBold
)
371 ncm
.cbSize
= sizeof(ncm
);
372 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
374 ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
378 ghMenuFont
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
379 if (ghMenuFont
== NULL
)
381 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
384 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
385 ghMenuFontBold
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
386 if (ghMenuFontBold
== NULL
)
388 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
389 GreDeleteObject(ghMenuFont
);
394 GreSetObjectOwner(ghMenuFont
, GDI_OBJ_HMGR_PUBLIC
);
395 GreSetObjectOwner(ghMenuFontBold
, GDI_OBJ_HMGR_PUBLIC
);
404 /**********************************************************************
407 * detect if there are loops in the menu tree (or the depth is too large)
409 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
415 if (!pmenu
) return depth
;
418 if( depth
> MAXMENUDEPTH
) return depth
;
419 item
= pmenu
->rgItems
;
421 for( i
= 0; i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
423 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
425 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
426 if( bdepth
> subdepth
) subdepth
= bdepth
;
428 if( subdepth
> MAXMENUDEPTH
)
429 TRACE("<- hmenu %p\n", item
->spSubMenu
);
435 /******************************************************************************
437 * UINT MenuGetStartOfNextColumn(
440 *****************************************************************************/
442 static UINT
MENU_GetStartOfNextColumn(
449 return NO_SELECTED_ITEM
;
452 if( i
== NO_SELECTED_ITEM
)
455 pItem
= menu
->rgItems
;
456 if (!pItem
) return NO_SELECTED_ITEM
;
458 for( ; i
< menu
->cItems
; ++i
) {
459 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
463 return NO_SELECTED_ITEM
;
466 /******************************************************************************
468 * UINT MenuGetStartOfPrevColumn(
471 *****************************************************************************/
472 static UINT
MENU_GetStartOfPrevColumn(
479 return NO_SELECTED_ITEM
;
481 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
482 return NO_SELECTED_ITEM
;
484 pItem
= menu
->rgItems
;
485 if (!pItem
) return NO_SELECTED_ITEM
;
487 /* Find the start of the column */
489 for(i
= menu
->iItem
; i
!= 0 &&
490 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
494 return NO_SELECTED_ITEM
;
496 for(--i
; i
!= 0; --i
) {
497 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
501 TRACE("ret %d.\n", i
);
506 /***********************************************************************
509 * Find a menu item. Return a pointer on the item, and modifies *hmenu
510 * in case the item was in a sub-menu.
512 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
515 ITEM
*fallback
= NULL
;
516 UINT fallback_pos
= 0;
519 if (!menu
) return NULL
;
521 if (wFlags
& MF_BYPOSITION
)
523 if (!menu
->cItems
) return NULL
;
524 if (*nPos
>= menu
->cItems
) return NULL
;
525 return &menu
->rgItems
[*nPos
];
529 PITEM item
= menu
->rgItems
;
530 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
534 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
535 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
541 else if (item
->wID
== *nPos
)
543 /* fallback to this item if nothing else found */
548 else if (item
->wID
== *nPos
)
557 *nPos
= fallback_pos
;
562 /***********************************************************************
565 * Find a Sub menu. Return the position of the submenu, and modifies
566 * *hmenu in case it is found in another sub-menu.
567 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
569 static UINT FASTCALL
MENU_FindSubMenu(PMENU
*menu
, PMENU SubTarget
)
574 item
= ((PMENU
)*menu
)->rgItems
;
575 for (i
= 0; i
< ((PMENU
)*menu
)->cItems
; i
++, item
++)
577 if (!item
->spSubMenu
)
581 if (item
->spSubMenu
== SubTarget
)
587 PMENU pSubMenu
= item
->spSubMenu
;
588 UINT pos
= MENU_FindSubMenu( &pSubMenu
, SubTarget
);
589 if (pos
!= NO_SELECTED_ITEM
)
597 return NO_SELECTED_ITEM
;
601 IntRemoveMenuItem( PMENU pMenu
, UINT nPos
, UINT wFlags
, BOOL bRecurse
)
605 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
606 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
610 FreeMenuText(pMenu
,item
);
611 if (bRecurse
&& item
->spSubMenu
)
613 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
);
615 ////// Use cAlloced with inc's of 8's....
616 if (--pMenu
->cItems
== 0)
618 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
619 pMenu
->rgItems
= NULL
;
623 while(nPos
< pMenu
->cItems
)
629 pMenu
->rgItems
= DesktopHeapReAlloc(pMenu
->head
.rpdesk
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
634 /**********************************************************************
637 * Insert (allocate) a new item into a menu.
639 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
643 /* Find where to insert new item */
645 if (flags
& MF_BYPOSITION
) {
646 if (pos
> menu
->cItems
)
649 if (!MENU_FindItem( &menu
, &pos
, flags
))
651 if (submenu
) *submenu
= menu
;
652 if (npos
) *npos
= pos
;
657 /* Make sure that MDI system buttons stay on the right side.
658 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
659 * regardless of their id.
662 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
663 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
666 TRACE("inserting at %u flags %x\n", pos
, flags
);
668 /* Create new items array */
670 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
673 WARN("allocation failed\n" );
676 if (menu
->cItems
> 0)
678 /* Copy the old array into the new one */
679 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
680 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
681 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
683 menu
->rgItems
= newItems
;
685 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
686 menu
->cyMenu
= 0; /* force size recalculate */
687 return &newItems
[pos
];
692 _In_ PMENU MenuObject
,
695 PROSMENUITEMINFO ItemInfo
,
696 PUNICODE_STRING lpstr
)
699 PMENU SubMenu
= NULL
;
701 NT_ASSERT(MenuObject
!= NULL
);
703 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
705 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
709 SubMenu
= MenuObject
;
711 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
713 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
715 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
719 /* Force size recalculation! */
721 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
723 TRACE("IntInsertMenuItemToList = %u %i\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
730 _Out_ PHANDLE Handle
,
732 _In_ PDESKTOP Desktop
,
733 _In_ PPROCESSINFO ppi
)
737 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
749 Menu
->cyMax
= 0; /* Default */
750 Menu
->hbrBack
= NULL
; /* No brush */
751 Menu
->dwContextHelpId
= 0; /* Default */
752 Menu
->dwMenuData
= 0; /* Default */
753 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
754 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
755 Menu
->spwndNotify
= NULL
;
756 Menu
->cyMenu
= 0; // Height
757 Menu
->cxMenu
= 0; // Width
758 Menu
->cItems
= 0; // Item count
761 Menu
->cxTextAlign
= 0;
762 Menu
->rgItems
= NULL
;
765 Menu
->TimeToHide
= FALSE
;
771 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
773 PITEM MenuItem
, NewMenuItem
= NULL
;
779 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, (Source
->cItems
+1) * sizeof(ITEM
));
780 if(!NewMenuItem
) return FALSE
;
782 RtlZeroMemory(NewMenuItem
, (Source
->cItems
+1) * sizeof(ITEM
));
784 Destination
->rgItems
= NewMenuItem
;
786 MenuItem
= Source
->rgItems
;
787 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
789 NewMenuItem
->fType
= MenuItem
->fType
;
790 NewMenuItem
->fState
= MenuItem
->fState
;
791 NewMenuItem
->wID
= MenuItem
->wID
;
792 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
793 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
794 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
795 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
796 if (MenuItem
->lpstr
.Length
)
798 NewMenuItem
->lpstr
.Length
= 0;
799 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
800 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
801 if (!NewMenuItem
->lpstr
.Buffer
)
803 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
806 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
807 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
808 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
812 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
813 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
815 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
821 IntCloneMenu(PMENU Source
)
829 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
830 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
832 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
839 Menu
->fFlags
= Source
->fFlags
;
840 Menu
->cyMax
= Source
->cyMax
;
841 Menu
->hbrBack
= Source
->hbrBack
;
842 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
843 Menu
->dwMenuData
= Source
->dwMenuData
;
844 Menu
->iItem
= NO_SELECTED_ITEM
;
845 Menu
->spwndNotify
= NULL
;
848 Menu
->cItems
= Source
->cItems
;
851 Menu
->cxTextAlign
= 0;
852 Menu
->rgItems
= NULL
;
855 Menu
->TimeToHide
= FALSE
;
857 IntCloneMenuItems(Menu
, Source
);
863 IntSetMenuFlagRtoL(PMENU Menu
)
865 ERR("SetMenuFlagRtoL\n");
866 Menu
->fFlags
|= MNF_RTOL
;
871 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
873 Menu
->dwContextHelpId
= dwContextHelpId
;
878 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
880 if(lpmi
->fMask
& MIM_BACKGROUND
)
881 lpmi
->hbrBack
= Menu
->hbrBack
;
882 if(lpmi
->fMask
& MIM_HELPID
)
883 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
884 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
885 lpmi
->cyMax
= Menu
->cyMax
;
886 if(lpmi
->fMask
& MIM_MENUDATA
)
887 lpmi
->dwMenuData
= Menu
->dwMenuData
;
888 if(lpmi
->fMask
& MIM_STYLE
)
889 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
891 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
893 lpmi
->cItems
= Menu
->cItems
;
895 lpmi
->iItem
= Menu
->iItem
;
896 lpmi
->cxMenu
= Menu
->cxMenu
;
897 lpmi
->cyMenu
= Menu
->cyMenu
;
898 lpmi
->spwndNotify
= Menu
->spwndNotify
;
899 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
900 lpmi
->iTop
= Menu
->iTop
;
901 lpmi
->iMaxTop
= Menu
->iMaxTop
;
902 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
904 lpmi
->fFlags
= Menu
->fFlags
;
905 lpmi
->Self
= Menu
->head
.h
;
906 lpmi
->TimeToHide
= Menu
->TimeToHide
;
907 lpmi
->Wnd
= Menu
->hWnd
;
913 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
915 if(lpmi
->fMask
& MIM_BACKGROUND
)
916 Menu
->hbrBack
= lpmi
->hbrBack
;
917 if(lpmi
->fMask
& MIM_HELPID
)
918 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
919 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
920 Menu
->cyMax
= lpmi
->cyMax
;
921 if(lpmi
->fMask
& MIM_MENUDATA
)
922 Menu
->dwMenuData
= lpmi
->dwMenuData
;
923 if(lpmi
->fMask
& MIM_STYLE
)
924 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
925 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
928 PITEM item
= Menu
->rgItems
;
929 for ( i
= Menu
->cItems
; i
; i
--, item
++)
931 if ( item
->spSubMenu
)
933 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
937 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
939 Menu
->iItem
= lpmi
->iItem
;
940 Menu
->cyMenu
= lpmi
->cyMenu
;
941 Menu
->cxMenu
= lpmi
->cxMenu
;
942 Menu
->spwndNotify
= lpmi
->spwndNotify
;
943 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
944 Menu
->iTop
= lpmi
->iTop
;
945 Menu
->iMaxTop
= lpmi
->iMaxTop
;
946 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
948 Menu
->TimeToHide
= lpmi
->TimeToHide
;
949 Menu
->hWnd
= lpmi
->Wnd
;
951 if ( lpmi
->fMask
& MIM_STYLE
)
953 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
954 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
955 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
961 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
962 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
966 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
968 lpmii
->fType
= MenuItem
->fType
;
970 if(lpmii
->fMask
& MIIM_BITMAP
)
972 lpmii
->hbmpItem
= MenuItem
->hbmp
;
974 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
976 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
977 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
979 if(lpmii
->fMask
& MIIM_DATA
)
981 lpmii
->dwItemData
= MenuItem
->dwItemData
;
983 if(lpmii
->fMask
& MIIM_ID
)
985 lpmii
->wID
= MenuItem
->wID
;
987 if(lpmii
->fMask
& MIIM_STATE
)
989 lpmii
->fState
= MenuItem
->fState
;
991 if(lpmii
->fMask
& MIIM_SUBMENU
)
993 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
996 if ((lpmii
->fMask
& MIIM_STRING
) ||
997 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
999 if (lpmii
->dwTypeData
== NULL
)
1001 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1004 { //// lpmii->lpstr can be read in user mode!!!!
1005 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1006 min(lpmii
->cch
* sizeof(WCHAR
),
1007 MenuItem
->lpstr
.MaximumLength
));
1008 if (! NT_SUCCESS(Status
))
1010 SetLastNtError(Status
);
1016 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1018 lpmii
->Rect
.left
= MenuItem
->xItem
;
1019 lpmii
->Rect
.top
= MenuItem
->yItem
;
1020 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1021 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1022 lpmii
->dxTab
= MenuItem
->dxTab
;
1023 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1024 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1025 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1032 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1034 PMENU SubMenuObject
;
1035 BOOL circref
= FALSE
;
1037 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1041 if ( lpmii
->fMask
& MIIM_FTYPE
)
1043 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1044 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1046 if (lpmii
->fMask
& MIIM_TYPE
)
1048 #if 0 //// Done in User32.
1049 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1051 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1052 KeRosDumpStackFrames(NULL
, 20);
1053 /* This does not happen on Win9x/ME */
1054 SetLastNtError( ERROR_INVALID_PARAMETER
);
1059 * Delete the menu item type when changing type from
1062 if (MenuItem
->fType
!= lpmii
->fType
&&
1063 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1065 FreeMenuText(MenuObject
,MenuItem
);
1066 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1067 MenuItem
->Xlpstr
= NULL
;
1069 if(lpmii
->fType
& MFT_BITMAP
)
1072 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1074 { /* Win 9x/Me stuff */
1075 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1077 lpmii
->dwTypeData
= 0;
1080 if(lpmii
->fMask
& MIIM_BITMAP
)
1082 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1083 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1084 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1086 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1088 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1090 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1091 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1093 if(lpmii
->fMask
& MIIM_DATA
)
1095 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1097 if(lpmii
->fMask
& MIIM_ID
)
1099 MenuItem
->wID
= lpmii
->wID
;
1101 if(lpmii
->fMask
& MIIM_STATE
)
1103 /* Remove MFS_DEFAULT flag from all other menu items if this item
1104 has the MFS_DEFAULT state */
1105 if(lpmii
->fState
& MFS_DEFAULT
)
1106 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1107 /* Update the menu item state flags */
1108 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1111 if(lpmii
->fMask
& MIIM_SUBMENU
)
1113 if (lpmii
->hSubMenu
)
1115 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1116 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1118 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1120 if (MenuObject
== SubMenuObject
)
1123 ERR("Pop Up Menu Double Trouble!\n");
1124 SubMenuObject
= IntCreateMenu(&hMenu
,
1126 MenuObject
->head
.rpdesk
,
1127 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1128 if (!SubMenuObject
) return FALSE
;
1129 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1132 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1134 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1135 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1138 /* Make sure the submenu is marked as a popup menu */
1139 SubMenuObject
->fFlags
|= MNF_POPUP
;
1140 // Now fix the test_subpopup_locked_by_menu tests....
1141 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1142 MenuItem
->spSubMenu
= SubMenuObject
;
1143 UserReferenceObject(SubMenuObject
);
1147 EngSetLastError( ERROR_INVALID_PARAMETER
);
1152 { // If submenu just dereference it.
1153 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1154 MenuItem
->spSubMenu
= NULL
;
1158 if ((lpmii
->fMask
& MIIM_STRING
) ||
1159 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1161 /* free the string when used */
1162 FreeMenuText(MenuObject
,MenuItem
);
1163 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1164 MenuItem
->Xlpstr
= NULL
;
1166 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1168 UNICODE_STRING Source
;
1170 Source
.Length
= Source
.MaximumLength
= lpmii
->cch
* sizeof(WCHAR
);
1171 Source
.Buffer
= lpmii
->dwTypeData
;
1173 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1174 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1176 MenuItem
->lpstr
.Length
= 0;
1177 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1178 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1179 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1181 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1182 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1187 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1188 !MenuItem
->Xlpstr
&&
1189 !lpmii
->dwTypeData
&&
1190 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1192 MenuItem
->fType
|= MFT_SEPARATOR
;
1194 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1196 MenuItem
->xItem
= lpmii
->Rect
.left
;
1197 MenuItem
->yItem
= lpmii
->Rect
.top
;
1198 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1199 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1200 MenuItem
->dxTab
= lpmii
->dxTab
;
1201 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1202 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1203 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1211 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1216 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1218 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1220 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1222 /* If the close item in the system menu change update the close button */
1225 switch (MenuItem
->wID
) // More than just close.
1233 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1235 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1237 /* Refresh the frame to reflect the change */
1238 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1240 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1243 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1253 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1258 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1260 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1262 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1268 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1271 PITEM MenuItem
= MenuObject
->rgItems
;
1273 if (!MenuItem
) return FALSE
;
1275 /* reset all default-item flags */
1276 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1278 MenuItem
->fState
&= ~MFS_DEFAULT
;
1281 /* no default item */
1282 if(uItem
== (UINT
)-1)
1286 MenuItem
= MenuObject
->rgItems
;
1289 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1290 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1295 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1297 if (MenuItem
->wID
== uItem
)
1299 MenuItem
->fState
|= MFS_DEFAULT
;
1309 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1312 PITEM MenuItem
= MenuObject
->rgItems
;
1315 if (!MenuItem
) return -1;
1317 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1320 if (i
>= MenuObject
->cItems
) return -1;
1323 /* default: don't return disabled items */
1324 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1326 /* search rekursiv when needed */
1327 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1331 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1333 if ( -1 != ret
) return ret
;
1335 /* when item not found in submenu, return the popup item */
1337 return ( fByPos
) ? i
: MenuItem
->wID
;
1347 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1348 return pItem
->spSubMenu
;
1351 /***********************************************************************
1352 * MenuInitSysMenuPopup
1354 * Grey the appropriate items in System menu.
1356 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1361 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1362 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1363 gray
= ((style
& WS_MAXIMIZE
) != 0);
1364 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1365 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1366 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1367 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1368 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1369 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1370 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1371 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1373 /* The menu item must keep its state if it's disabled */
1375 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1377 /* Set default menu item */
1378 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1379 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1380 else DefItem
= SC_CLOSE
;
1382 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1386 /***********************************************************************
1387 * MenuDrawPopupGlyph
1389 * Draws popup magic glyphs (can be found in system menu).
1391 static void FASTCALL
1392 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1395 HFONT hFont
, hOldFont
;
1401 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1404 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1407 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1410 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1414 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1417 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1418 RECTL_vInflateRect(r
, -2, -2);
1419 lf
.lfHeight
= r
->bottom
- r
->top
;
1421 lf
.lfWeight
= FW_NORMAL
;
1422 lf
.lfCharSet
= DEFAULT_CHARSET
;
1423 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1424 hFont
= GreCreateFontIndirectW(&lf
);
1425 /* save font and text color */
1426 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1427 clrsave
= GreGetTextColor(dc
);
1428 bkmode
= GreGetBkMode(dc
);
1429 /* set color and drawing mode */
1430 IntGdiSetBkMode(dc
, TRANSPARENT
);
1436 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1437 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1440 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1441 /* draw selected symbol */
1442 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1443 /* restore previous settings */
1444 IntGdiSetTextColor(dc
, clrsave
);
1445 NtGdiSelectFont(dc
, hOldFont
);
1446 IntGdiSetBkMode(dc
, bkmode
);
1447 GreDeleteObject(hFont
);
1450 /***********************************************************************
1451 * MENU_AdjustMenuItemRect
1453 * Adjust menu item rectangle according to scrolling state.
1456 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1458 if (menu
->dwArrowsOn
)
1460 UINT arrow_bitmap_height
;
1461 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1462 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1463 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1467 /***********************************************************************
1468 * MENU_FindItemByCoords
1470 * Find the item at the specified coordinates (screen coords). Does
1471 * not work for child windows and therefore should not be called for
1472 * an arbitrary system menu.
1474 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1479 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1481 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1482 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1483 pt
.x
= rect
.right
- 1 - pt
.x
;
1487 item
= menu
->rgItems
;
1488 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1490 //rect = item->rect;
1491 rect
.left
= item
->xItem
;
1492 rect
.top
= item
->yItem
;
1493 rect
.right
= item
->cxItem
; // Do this for now......
1494 rect
.bottom
= item
->cyItem
;
1496 MENU_AdjustMenuItemRect(menu
, &rect
);
1497 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1506 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1508 MENU
*menu
= UserGetMenuObject(hMenu
);
1511 /*FIXME: Do we have to handle hWnd here? */
1512 if (!menu
) return -1;
1513 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1517 /***********************************************************************
1520 * Find the menu item selected by a key press.
1521 * Return item id, -1 if none, -2 if we should close the menu.
1523 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1524 WCHAR Key
, BOOL ForceMenuChar
)
1529 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1531 if (!menu
|| !VerifyMenu(menu
))
1532 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1535 ITEM
*item
= menu
->rgItems
;
1537 if ( !ForceMenuChar
)
1540 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1542 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1544 LPWSTR text
= item
->Xlpstr
;
1547 const WCHAR
*p
= text
- 2;
1550 const WCHAR
*q
= p
+ 2;
1551 p
= wcschr (q
, '&');
1552 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1554 while (p
!= NULL
&& p
[1] == '&');
1555 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1560 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1561 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1563 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1564 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1565 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1566 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1571 /***********************************************************************
1572 * MenuGetBitmapItemSize
1574 * Get the size of a bitmap item.
1576 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1579 HBITMAP bmp
= lpitem
->hbmp
;
1581 size
->cx
= size
->cy
= 0;
1583 /* check if there is a magic menu item associated with this item */
1584 if (IS_MAGIC_BITMAP(bmp
))
1586 switch((INT_PTR
) bmp
)
1588 case (INT_PTR
)HBMMENU_CALLBACK
:
1590 MEASUREITEMSTRUCT measItem
;
1591 measItem
.CtlType
= ODT_MENU
;
1593 measItem
.itemID
= lpitem
->wID
;
1594 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1595 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1596 measItem
.itemData
= lpitem
->dwItemData
;
1597 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1598 size
->cx
= measItem
.itemWidth
;
1599 size
->cy
= measItem
.itemHeight
;
1600 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1605 case (INT_PTR
) HBMMENU_SYSTEM
:
1606 if (lpitem
->dwItemData
)
1608 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1612 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1613 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1614 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1615 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1616 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1617 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1618 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1619 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1620 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1621 /* FIXME: Why we need to subtract these magic values? */
1622 /* to make them smaller than the menu bar? */
1623 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1624 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1629 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1631 size
->cx
= bm
.bmWidth
;
1632 size
->cy
= bm
.bmHeight
;
1636 /***********************************************************************
1637 * MenuDrawBitmapItem
1639 * Draw a bitmap item.
1641 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1642 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1648 int w
= rect
->right
- rect
->left
;
1649 int h
= rect
->bottom
- rect
->top
;
1650 int bmp_xoffset
= 0;
1652 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1655 /* Check if there is a magic menu item associated with this item */
1656 if (IS_MAGIC_BITMAP(hbmToDraw
))
1662 switch ((INT_PTR
)hbmToDraw
)
1664 case (INT_PTR
)HBMMENU_SYSTEM
:
1665 if (lpitem
->dwItemData
)
1667 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1669 ERR("Get Item Data from this Window!!!\n");
1672 ERR("Draw Bitmap\n");
1673 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1674 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1678 PCURICON_OBJECT pIcon
= NULL
;
1679 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1681 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1682 /* only use right half of the bitmap */
1683 //bmp_xoffset = bm.bmWidth / 2;
1684 //bm.bmWidth -= bmp_xoffset;
1687 pIcon
= NC_IconForWindow(WndOwner
);
1688 // FIXME: NC_IconForWindow should reference it for us */
1689 if (pIcon
) UserReferenceObject(pIcon
);
1694 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1695 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1696 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1697 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1698 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1699 UserDereferenceObject(pIcon
);
1704 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1705 flags
= DFCS_CAPTIONRESTORE
;
1707 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1709 flags
= DFCS_CAPTIONMIN
;
1711 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1713 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1715 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1716 flags
= DFCS_CAPTIONCLOSE
;
1718 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1719 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1721 case (INT_PTR
)HBMMENU_CALLBACK
:
1723 DRAWITEMSTRUCT drawItem
;
1725 drawItem
.CtlType
= ODT_MENU
;
1727 drawItem
.itemID
= lpitem
->wID
;
1728 drawItem
.itemAction
= odaction
;
1729 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1730 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1731 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1732 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1733 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1734 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1735 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1736 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1738 drawItem
.rcItem
= *rect
;
1739 drawItem
.itemData
= lpitem
->dwItemData
;
1740 /* some applications make this assumption on the DC's origin */
1741 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1742 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1743 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1744 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1749 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1750 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1751 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1752 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1753 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1756 RECTL_vInflateRect(&r
, -1, -1);
1757 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1758 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1762 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1765 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1766 NtGdiSelectBitmap( hdcMem
, bmp
);
1767 /* handle fontsize > bitmap_height */
1768 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1770 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1771 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1772 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1773 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1774 IntGdiDeleteDC( hdcMem
, FALSE
);
1778 IntGetDialogBaseUnits(VOID
)
1787 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1789 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1790 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1791 UserReleaseDC( 0, hdc
, FALSE
);
1798 /***********************************************************************
1801 * Calculate the size of the menu item and store it in lpitem->rect.
1803 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1804 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1807 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1808 UINT arrow_bitmap_width
;
1812 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1814 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1816 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1818 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1820 if (lpitem
->fType
& MF_OWNERDRAW
)
1822 MEASUREITEMSTRUCT mis
;
1823 mis
.CtlType
= ODT_MENU
;
1825 mis
.itemID
= lpitem
->wID
;
1826 mis
.itemData
= lpitem
->dwItemData
;
1827 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1829 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1830 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1831 * width of a menufont character to the width of an owner-drawn menu.
1833 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1835 /* under at least win95 you seem to be given a standard
1836 height for the menu and the height value is ignored */
1837 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1839 Rect
.bottom
+= mis
.itemHeight
;
1841 //lpitem->cxBmp = mis.itemWidth;
1842 //lpitem->cyBmp = mis.itemHeight;
1843 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1844 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1845 lpitem
->wID
, Rect
.right
-Rect
.left
,
1846 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1848 lpitem
->xItem
= Rect
.left
;
1849 lpitem
->yItem
= Rect
.top
;
1850 lpitem
->cxItem
= Rect
.right
;
1851 lpitem
->cyItem
= Rect
.bottom
;
1856 lpitem
->xItem
= orgX
;
1857 lpitem
->yItem
= orgY
;
1858 lpitem
->cxItem
= orgX
;
1859 lpitem
->cyItem
= orgY
;
1861 if (lpitem
->fType
& MF_SEPARATOR
)
1863 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1865 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1876 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1877 /* Keep the size of the bitmap in callback mode to be able
1878 * to draw it correctly */
1879 lpitem
->cxBmp
= size
.cx
;
1880 lpitem
->cyBmp
= size
.cy
;
1881 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1882 lpitem
->cxItem
+= size
.cx
+ 2;
1883 itemheight
= size
.cy
+ 2;
1885 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1886 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1887 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1888 lpitem
->dxTab
= lpitem
->cxItem
;
1889 lpitem
->cxItem
+= arrow_bitmap_width
;
1890 } else /* hbmpItem & MenuBar */ {
1891 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1892 lpitem
->cxItem
+= size
.cx
;
1893 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1894 itemheight
= size
.cy
;
1896 /* Special case: Minimize button doesn't have a space behind it. */
1897 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1898 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1899 lpitem
->cxItem
-= 1;
1902 else if (!menuBar
) {
1903 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1904 lpitem
->cxItem
+= check_bitmap_width
;
1905 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1906 lpitem
->dxTab
= lpitem
->cxItem
;
1907 lpitem
->cxItem
+= arrow_bitmap_width
;
1910 /* it must be a text item - unless it's the system menu */
1911 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1912 HFONT hfontOld
= NULL
;
1913 RECT rc
;// = lpitem->Rect;
1914 LONG txtheight
, txtwidth
;
1916 rc
.left
= lpitem
->xItem
;
1917 rc
.top
= lpitem
->yItem
;
1918 rc
.right
= lpitem
->cxItem
; // Do this for now......
1919 rc
.bottom
= lpitem
->cyItem
;
1921 if ( lpitem
->fState
& MFS_DEFAULT
) {
1922 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1925 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1927 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1928 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1930 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1932 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1935 int n
= (int)( p
- lpitem
->Xlpstr
);
1936 /* Item contains a tab (only meaningful in popup menus) */
1937 /* get text size before the tab */
1938 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1939 DT_SINGLELINE
|DT_CALCRECT
);
1940 txtwidth
= rc
.right
- rc
.left
;
1941 p
+= 1; /* advance past the Tab */
1942 /* get text size after the tab */
1943 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1944 DT_SINGLELINE
|DT_CALCRECT
);
1945 lpitem
->dxTab
+= txtwidth
;
1946 txtheight
= max( txtheight
, tmpheight
);
1947 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1948 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1950 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1951 DT_SINGLELINE
|DT_CALCRECT
);
1952 txtwidth
= rc
.right
- rc
.left
;
1953 lpitem
->dxTab
+= txtwidth
;
1955 lpitem
->cxItem
+= 2 + txtwidth
;
1956 itemheight
= max( itemheight
,
1957 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1961 NtGdiSelectFont (hdc
, hfontOld
);
1963 } else if( menuBar
) {
1964 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1966 lpitem
->cyItem
+= itemheight
;
1967 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1970 /***********************************************************************
1971 * MENU_GetMaxPopupHeight
1974 MENU_GetMaxPopupHeight(PMENU lppop
)
1978 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1979 return lppop
->cyMax
;
1981 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
1982 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
1985 /***********************************************************************
1986 * MenuPopupMenuCalcSize
1988 * Calculate the size of a popup menu.
1990 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
1995 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1996 BOOL textandbmp
= FALSE
;
1998 Menu
->cxMenu
= Menu
->cyMenu
= 0;
1999 if (Menu
->cItems
== 0) return;
2001 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2003 NtGdiSelectFont( hdc
, ghMenuFont
);
2008 Menu
->cxTextAlign
= 0;
2010 while (start
< Menu
->cItems
)
2012 lpitem
= &Menu
->rgItems
[start
];
2014 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2015 orgX
+= MENU_COL_SPACE
;
2016 orgY
= MENU_TOP_MARGIN
;
2018 maxTab
= maxTabWidth
= 0;
2019 /* Parse items until column break or end of menu */
2020 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2023 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2025 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2026 maxX
= max(maxX
, lpitem
->cxItem
);
2027 orgY
= lpitem
->cyItem
;
2028 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2030 maxTab
= max( maxTab
, lpitem
->dxTab
);
2031 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2033 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2036 /* Finish the column (set all items to the largest width found) */
2037 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2038 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2040 lpitem
->cxItem
= maxX
;
2041 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2042 lpitem
->dxTab
= maxTab
;
2044 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2047 Menu
->cxMenu
= maxX
;
2048 /* if none of the items have both text and bitmap then
2049 * the text and bitmaps are all aligned on the left. If there is at
2050 * least one item with both text and bitmap then bitmaps are
2051 * on the left and texts left aligned with the right hand side
2053 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2055 /* space for 3d border */
2056 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2059 /* Adjust popup height if it exceeds maximum */
2060 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2061 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2062 if (Menu
->cyMenu
>= maxHeight
)
2064 Menu
->cyMenu
= maxHeight
;
2065 Menu
->dwArrowsOn
= 1;
2069 Menu
->dwArrowsOn
= 0;
2071 UserReleaseDC( 0, hdc
, FALSE
);
2074 /***********************************************************************
2075 * MENU_MenuBarCalcSize
2077 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2078 * height is off by 1 pixel which causes lengthy window relocations when
2079 * active document window is maximized/restored.
2081 * Calculate the size of the menu bar.
2083 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2086 UINT start
, i
, helpPos
;
2087 int orgX
, orgY
, maxY
;
2089 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2090 if (lppop
->cItems
== 0) return;
2091 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2092 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2094 maxY
= lprect
->top
+1;
2097 lppop
->cxTextAlign
= 0;
2098 while (start
< lppop
->cItems
)
2100 lpitem
= &lppop
->rgItems
[start
];
2101 orgX
= lprect
->left
;
2104 /* Parse items until line break or end of menu */
2105 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2107 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2109 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2111 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2112 //debug_print_menuitem (" item: ", lpitem, "");
2113 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2114 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2116 if (lpitem
->cxItem
> lprect
->right
)
2118 if (i
!= start
) break;
2119 else lpitem
->cxItem
= lprect
->right
;
2121 maxY
= max( maxY
, lpitem
->cyItem
);
2122 orgX
= lpitem
->cxItem
;
2125 /* Finish the line (set all items to the largest height found) */
2127 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2128 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2130 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2132 start
= i
; /* This works! */
2135 lprect
->bottom
= maxY
;
2136 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2138 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2139 /* the last item (if several lines, only move the last line) */
2140 if (helpPos
== ~0U) return;
2141 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2142 orgY
= lpitem
->yItem
;
2143 orgX
= lprect
->right
;
2144 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2145 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2146 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2147 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2148 lpitem
->cxItem
= orgX
;
2149 orgX
= lpitem
->xItem
;
2153 /***********************************************************************
2154 * MENU_DrawScrollArrows
2156 * Draw scroll arrows.
2158 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2160 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2164 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2165 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2169 rect
.right
= lppop
->cxMenu
;
2170 rect
.bottom
= arrow_bitmap_height
;
2171 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2172 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2174 dfcrc
.right
= arrow_bitmap_width
;
2175 dfcrc
.bottom
= arrow_bitmap_height
;
2176 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2178 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2179 rect
.bottom
= lppop
->cyMenu
;
2180 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2181 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2182 Flags
= DFCS_INACTIVE
;
2183 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2184 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2185 dfcrc
.right
= arrow_bitmap_width
;
2186 dfcrc
.bottom
= lppop
->cyMenu
;
2187 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2190 /***********************************************************************
2193 * Draw a single menu item.
2195 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2196 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2200 BOOL flat_menu
= FALSE
;
2202 UINT arrow_bitmap_width
= 0;
2205 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2208 if (lpitem
->fType
& MF_SYSMENU
)
2210 if (!(Wnd
->style
& WS_MINIMIZE
))
2212 NC_GetInsideRect(Wnd
, &rect
);
2213 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2218 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2219 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2223 if (lpitem
->fState
& MF_HILITE
)
2225 if(menuBar
&& !flat_menu
) {
2226 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2227 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2229 if (lpitem
->fState
& MF_GRAYED
)
2230 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2232 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2233 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2238 if (lpitem
->fState
& MF_GRAYED
)
2239 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2241 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2242 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2245 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2246 //rect = lpitem->Rect;
2247 rect
.left
= lpitem
->xItem
;
2248 rect
.top
= lpitem
->yItem
;
2249 rect
.right
= lpitem
->cxItem
; // Do this for now......
2250 rect
.bottom
= lpitem
->cyItem
;
2252 MENU_AdjustMenuItemRect(Menu
, &rect
);
2254 if (lpitem
->fType
& MF_OWNERDRAW
)
2257 ** Experimentation under Windows reveals that an owner-drawn
2258 ** menu is given the rectangle which includes the space it requested
2259 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2260 ** and a popup-menu arrow. This is the value of lpitem->rect.
2261 ** Windows will leave all drawing to the application except for
2262 ** the popup-menu arrow. Windows always draws that itself, after
2263 ** the menu owner has finished drawing.
2266 COLORREF old_bk
, old_text
;
2268 dis
.CtlType
= ODT_MENU
;
2270 dis
.itemID
= lpitem
->wID
;
2271 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2273 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2274 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2275 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2276 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2277 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2278 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2279 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2280 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2281 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2284 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2285 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2286 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2287 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2289 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2290 old_bk
= GreGetBkColor(hdc
);
2291 old_text
= GreGetTextColor(hdc
);
2292 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2293 IntGdiSetBkColor(hdc
, old_bk
);
2294 IntGdiSetTextColor(hdc
, old_text
);
2295 /* Draw the popup-menu arrow */
2296 if (!menuBar
&& lpitem
->spSubMenu
)
2299 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2300 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2301 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2306 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2308 if (lpitem
->fState
& MF_HILITE
)
2312 RECTL_vInflateRect (&rect
, -1, -1);
2313 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2314 RECTL_vInflateRect (&rect
, 1, 1);
2315 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2320 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2322 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2326 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2328 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2330 /* vertical separator */
2331 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2336 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2338 rc
.bottom
= Height
- 3;
2341 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2342 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2343 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2344 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2345 NtGdiSelectPen( hdc
, oldPen
);
2348 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2351 /* horizontal separator */
2352 if (lpitem
->fType
& MF_SEPARATOR
)
2359 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
2362 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2363 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2364 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2365 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2366 NtGdiSelectPen( hdc
, oldPen
);
2369 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2374 /* helper lines for debugging */
2375 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2376 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2377 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2378 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2379 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2380 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2386 INT y
= rect
.top
+ rect
.bottom
;
2388 BOOL checked
= FALSE
;
2389 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2390 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2391 /* Draw the check mark
2394 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2396 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2397 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2398 lpitem
->hbmpUnchecked
;
2399 if (bm
) /* we have a custom bitmap */
2401 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2403 NtGdiSelectBitmap( hdcMem
, bm
);
2404 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2405 check_bitmap_width
, check_bitmap_height
,
2406 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2407 IntGdiDeleteDC( hdcMem
, FALSE
);
2410 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2414 r
.right
= r
.left
+ UserGetSystemMetrics(SM_CXMENUCHECK
);
2415 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2416 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2417 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2421 if ( lpitem
->hbmp
)//&& !( checked && (Menu->dwStyle & MNS_CHECKORBMP)))
2424 //CopyRect(&bmpRect, &rect);
2426 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2427 bmpRect
.left
+= check_bitmap_width
+ 2;
2428 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2431 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2432 /* some applications make this assumption on the DC's origin */
2433 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
2434 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2435 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
2438 /* Draw the popup-menu arrow */
2439 if (lpitem
->spSubMenu
)
2442 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2443 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2444 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2447 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2448 rect
.left
+= check_bitmap_width
;
2449 rect
.right
-= arrow_bitmap_width
;//check_bitmap_width;
2451 else if( lpitem
->hbmp
)
2452 { /* Draw the bitmap */
2455 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
2456 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
, Menu
, WndOwner
, odaction
, menuBar
);
2457 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
2460 /* process text if present */
2466 UINT uFormat
= menuBar
?
2467 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2468 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2470 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2471 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2473 rect
.left
+= Menu
->cxTextAlign
;
2475 if ( lpitem
->fState
& MFS_DEFAULT
)
2477 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2482 rect
.left
+= lpitem
->cxBmp
;
2483 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2484 rect
.left
+= MenuCharSize
.cx
;
2485 rect
.right
-= MenuCharSize
.cx
;
2486 //rect.left += MENU_BAR_ITEMS_SPACE / 2;
2487 //rect.right -= MENU_BAR_ITEMS_SPACE / 2;
2490 Text
= lpitem
->Xlpstr
;
2493 for (i
= 0; L
'\0' != Text
[i
]; i
++)
2494 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2498 if(lpitem
->fState
& MF_GRAYED
)
2500 if (!(lpitem
->fState
& MF_HILITE
) )
2502 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2503 IntGdiSetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
2504 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2505 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2507 IntGdiSetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
2509 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2511 /* paint the shortcut text */
2512 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2514 if (L
'\t' == Text
[i
])
2516 rect
.left
= lpitem
->dxTab
;
2517 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2521 rect
.right
= lpitem
->dxTab
;
2522 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2525 if (lpitem
->fState
& MF_GRAYED
)
2527 if (!(lpitem
->fState
& MF_HILITE
) )
2529 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2530 IntGdiSetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
2531 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2532 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2534 IntGdiSetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
2536 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2541 NtGdiSelectFont (hdc
, hfontOld
);
2546 /***********************************************************************
2549 * Paint a popup menu.
2551 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2553 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2556 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2558 IntGetClientRect( wnd
, &rect
);
2560 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2561 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2562 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2566 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2568 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2571 BOOL flat_menu
= FALSE
;
2573 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2575 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2577 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2579 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2580 /* draw menu items */
2581 if (menu
&& menu
->cItems
)
2586 item
= menu
->rgItems
;
2587 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2589 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2590 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2592 /* draw scroll arrows */
2593 if (menu
->dwArrowsOn
)
2595 MENU_DrawScrollArrows(menu
, hdc
);
2601 NtGdiSelectBrush( hdc
, hPrevBrush
);
2606 /**********************************************************************
2609 PWND
MENU_IsMenuActive(VOID
)
2611 return ValidateHwndNoErr(top_popup
);
2614 /**********************************************************************
2617 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2619 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2621 void MENU_EndMenu( PWND pwnd
)
2624 menu
= UserGetMenuObject(top_popup_hmenu
);
2625 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2627 if (fInsideMenuLoop
&& top_popup
)
2629 fInsideMenuLoop
= FALSE
;
2633 ERR("Already in End loop\n");
2638 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2644 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2647 HFONT FontOld
= NULL
;
2648 BOOL flat_menu
= FALSE
;
2650 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2654 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2662 if (Rect
== NULL
|| !pMenu
)
2664 return UserGetSystemMetrics(SM_CYMENU
);
2667 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2669 FontOld
= NtGdiSelectFont(hDC
, Font
);
2671 if (pMenu
->cyMenu
== 0)
2673 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2676 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2678 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2680 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2681 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2682 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2683 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2685 if (pMenu
->cItems
== 0)
2687 NtGdiSelectFont(hDC
, FontOld
);
2688 return UserGetSystemMetrics(SM_CYMENU
);
2691 for (i
= 0; i
< pMenu
->cItems
; i
++)
2693 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2696 NtGdiSelectFont(hDC
, FontOld
);
2698 return pMenu
->cyMenu
;
2701 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2704 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2708 // No menu. Do not reserve any space
2714 return UserGetSystemMetrics(SM_CYMENU
);
2719 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2721 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2723 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2725 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2727 return lppop
->cyMenu
;
2731 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2735 /***********************************************************************
2738 * Popup menu initialization before WM_ENTERMENULOOP.
2740 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2743 PPOPUPMENU pPopupMenu
;
2745 LARGE_STRING WindowName
;
2746 UNICODE_STRING ClassName
;
2747 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2749 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2751 menu
->spwndNotify
= pWndOwner
;
2753 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2754 ex_style
= WS_EX_LAYOUTRTL
;
2756 ClassName
.Buffer
= WC_MENU
;
2757 ClassName
.Length
= 0;
2759 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2760 RtlZeroMemory(&Cs
, sizeof(Cs
));
2761 Cs
.style
= WS_POPUP
;
2762 Cs
.dwExStyle
= ex_style
;
2763 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2764 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2765 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2766 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2767 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2769 /* NOTE: In Windows, top menu popup is not owned. */
2770 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2772 if( !pWndCreated
) return FALSE
;
2775 // Setup pop up menu structure.
2777 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2779 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2781 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2782 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2783 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2785 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2786 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2787 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2788 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2789 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2791 if (pPopupMenu
->fRightButton
)
2792 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2794 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2796 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2797 menu
->fFlags
& MNF_RTOL
)
2799 pPopupMenu
->fDroppedLeft
= TRUE
;
2804 /***********************************************************************
2807 * Display a popup menu.
2809 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2810 INT x
, INT y
, INT xanchor
, INT yanchor
)
2816 USER_REFERENCE_ENTRY Ref
;
2818 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2819 pwndOwner
, menu
, id
, x
, y
, xanchor
, yanchor
);
2821 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2823 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2824 menu
->iItem
= NO_SELECTED_ITEM
;
2827 menu
->dwArrowsOn
= 0;
2828 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2830 /* adjust popup menu pos so that it fits within the desktop */
2832 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2833 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2835 /* FIXME: should use item rect */
2838 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2840 if (flags
& TPM_LAYOUTRTL
)
2841 flags
^= TPM_RIGHTALIGN
;
2843 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2844 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2846 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2847 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2849 if( x
+ width
> monitor
->rcMonitor
.right
)
2851 if( xanchor
&& x
>= width
- xanchor
)
2852 x
-= width
- xanchor
;
2854 if( x
+ width
> monitor
->rcMonitor
.right
)
2855 x
= monitor
->rcMonitor
.right
- width
;
2857 if( x
< monitor
->rcMonitor
.left
) x
= monitor
->rcMonitor
.left
;
2859 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2861 if( yanchor
&& y
>= height
+ yanchor
)
2862 y
-= height
+ yanchor
;
2864 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2865 y
= monitor
->rcMonitor
.bottom
- height
;
2867 if( y
< monitor
->rcMonitor
.top
) y
= monitor
->rcMonitor
.top
;
2869 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2873 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2878 top_popup
= menu
->hWnd
;
2879 top_popup_hmenu
= UserHMGetHandle(menu
);
2882 /* Display the window */
2883 UserRefObjectCo(pWnd
, &Ref
);
2884 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2886 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2888 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2889 UserDerefObjectCo(pWnd
);
2894 /***********************************************************************
2895 * MENU_EnsureMenuItemVisible
2897 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2899 USER_REFERENCE_ENTRY Ref
;
2900 if (lppop
->dwArrowsOn
)
2902 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2903 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2904 UINT nOldPos
= lppop
->iTop
;
2906 UINT arrow_bitmap_height
;
2907 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2909 IntGetClientRect(pWnd
, &rc
);
2911 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2913 rc
.top
+= arrow_bitmap_height
;
2914 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2916 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2917 UserRefObjectCo(pWnd
, &Ref
);
2918 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
2920 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
2921 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2922 MENU_DrawScrollArrows(lppop
, hdc
);
2923 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2925 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
2927 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
2928 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2929 MENU_DrawScrollArrows(lppop
, hdc
);
2930 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2932 UserDerefObjectCo(pWnd
);
2936 /***********************************************************************
2939 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
2940 BOOL sendMenuSelect
, PMENU topmenu
)
2945 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
2947 if (!menu
|| !menu
->cItems
) return;
2949 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
2953 if (menu
->iItem
== wIndex
) return;
2955 if (menu
->fFlags
& MNF_POPUP
)
2956 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
2958 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2961 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
2962 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
2963 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
2966 NtGdiSelectFont( hdc
, ghMenuFont
);
2968 /* Clear previous highlighted item */
2969 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2971 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2972 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
2973 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
2977 /* Highlight new item (if any) */
2978 menu
->iItem
= wIndex
;
2979 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2981 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
2983 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
2984 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
2985 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
2986 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
2990 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
2991 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
2992 ip
->fType
| ip
->fState
|
2993 (ip
->spSubMenu
? MF_POPUP
: 0) |
2994 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
2996 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
2999 else if (sendMenuSelect
)
3004 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3005 if (pos
!= NO_SELECTED_ITEM
)
3007 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3008 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3009 (ip
->spSubMenu
? MF_POPUP
: 0) |
3010 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3012 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3016 UserReleaseDC(pWnd
, hdc
, FALSE
);
3019 /***********************************************************************
3022 * Moves currently selected item according to the Offset parameter.
3023 * If there is no selection then it should select the last item if
3024 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3026 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3030 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3032 if ((!menu
) || (!menu
->rgItems
)) return;
3034 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3036 if ( menu
->cItems
== 1 )
3039 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3041 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3043 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3048 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3049 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3050 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3052 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3057 /***********************************************************************
3060 * Hide the sub-popup menus of this menu.
3062 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3063 BOOL SendMenuSelect
, UINT wFlags
)
3065 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3067 if ( Menu
&& top_popup
)
3071 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3073 Item
= &Menu
->rgItems
[Menu
->iItem
];
3074 if (!(Item
->spSubMenu
) ||
3075 !(Item
->fState
& MF_MOUSESELECT
)) return;
3076 Item
->fState
&= ~MF_MOUSESELECT
;
3081 if (Item
->spSubMenu
)
3084 if (!VerifyMenu(Item
->spSubMenu
)) return;
3085 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3086 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3087 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3088 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3089 co_UserDestroyWindow(pWnd
);
3091 /* Native returns handle to destroyed window */
3092 if (!(wFlags
& TPM_NONOTIFY
))
3094 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3095 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3098 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3099 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3101 Item
->spSubMenu
->hWnd
= NULL
;
3107 /***********************************************************************
3110 * Display the sub-menu of the selected item of this menu.
3111 * Return the handle of the submenu, or menu if no submenu to display.
3113 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3120 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3122 if (!Menu
) return Menu
;
3124 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3126 Item
= &Menu
->rgItems
[Menu
->iItem
];
3127 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3130 /* message must be sent before using item,
3131 because nearly everything may be changed by the application ! */
3133 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3134 if (!(Flags
& TPM_NONOTIFY
))
3136 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3137 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3138 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3141 Item
= &Menu
->rgItems
[Menu
->iItem
];
3142 //Rect = ItemInfo.Rect;
3143 Rect
.left
= Item
->xItem
;
3144 Rect
.top
= Item
->yItem
;
3145 Rect
.right
= Item
->cxItem
; // Do this for now......
3146 Rect
.bottom
= Item
->cyItem
;
3148 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3150 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3151 if (!(Item
->fState
& MF_HILITE
))
3153 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3154 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3156 NtGdiSelectFont(Dc
, ghMenuFont
);
3158 Item
->fState
|= MF_HILITE
;
3159 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3160 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3162 UserReleaseDC(pWnd
, Dc
, FALSE
);
3165 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3167 Item
->xItem
= Rect
.left
;
3168 Item
->yItem
= Rect
.top
;
3169 Item
->cxItem
= Rect
.right
; // Do this for now......
3170 Item
->cyItem
= Rect
.bottom
;
3172 Item
->fState
|= MF_MOUSESELECT
;
3174 if (IS_SYSTEM_MENU(Menu
))
3176 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3178 NC_GetSysPopupPos(pWnd
, &Rect
);
3179 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3180 Rect
.top
= Rect
.bottom
;
3181 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3182 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3186 IntGetWindowRect(pWnd
, &Rect
);
3187 if (Menu
->fFlags
& MNF_POPUP
)
3190 rc
.left
= Item
->xItem
;
3191 rc
.top
= Item
->yItem
;
3192 rc
.right
= Item
->cxItem
; // Do this for now......
3193 rc
.bottom
= Item
->cyItem
;
3195 MENU_AdjustMenuItemRect(Menu
, &rc
);
3197 /* The first item in the popup menu has to be at the
3198 same y position as the focused menu item */
3199 if(Flags
& TPM_LAYOUTRTL
)
3200 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3202 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3203 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3204 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3205 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3206 - UserGetSystemMetrics(SM_CYBORDER
);
3210 if(Flags
& TPM_LAYOUTRTL
)
3211 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3213 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3214 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3215 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3216 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3220 /* use default alignment for submenus */
3221 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3223 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3225 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3226 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3229 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3231 return Item
->spSubMenu
;
3234 /***********************************************************************
3235 * MenuExecFocusedItem
3237 * Execute a menu item (for instance when user pressed Enter).
3238 * Return the wID of the executed item. Otherwise, -1 indicating
3239 * that no menu item was executed, -2 if a popup is shown;
3240 * Have to receive the flags for the TrackPopupMenu options to avoid
3241 * sending unwanted message.
3244 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3248 TRACE("%p menu=%p\n", pmt
, Menu
);
3250 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3255 Item
= &Menu
->rgItems
[Menu
->iItem
];
3257 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3259 if (!(Item
->spSubMenu
))
3261 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3263 /* If TPM_RETURNCMD is set you return the id, but
3264 do not send a message to the owner */
3265 if (!(Flags
& TPM_RETURNCMD
))
3267 if (Menu
->fFlags
& MNF_SYSMENU
)
3269 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3270 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3274 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3276 if (dwStyle
& MNS_NOTIFYBYPOS
)
3277 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3279 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3287 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3294 /***********************************************************************
3295 * MenuSwitchTracking
3297 * Helper function for menu navigation routines.
3299 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3301 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3303 if ( pmt
->TopMenu
!= PtMenu
&&
3304 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3306 /* both are top level menus (system and menu-bar) */
3307 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3308 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3309 pmt
->TopMenu
= PtMenu
;
3313 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3316 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3319 /***********************************************************************
3322 * Return TRUE if we can go on with menu tracking.
3324 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3326 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3332 if (IS_SYSTEM_MENU(PtMenu
))
3334 item
= PtMenu
->rgItems
;
3338 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3343 if (PtMenu
->iItem
!= id
)
3344 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3346 /* If the popup menu is not already "popped" */
3347 if (!(item
->fState
& MF_MOUSESELECT
))
3349 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3354 /* Else the click was on the menu bar, finish the tracking */
3359 /***********************************************************************
3362 * Return the value of MenuExecFocusedItem if
3363 * the selected item was not a popup. Else open the popup.
3364 * A -1 return value indicates that we go on with menu tracking.
3367 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3369 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3376 if ( IS_SYSTEM_MENU(PtMenu
) )
3378 item
= PtMenu
->rgItems
;
3382 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3385 if (item
&& ( PtMenu
->iItem
== Id
))
3387 if (!(item
->spSubMenu
))
3389 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3390 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3391 return ExecutedMenuId
;
3394 /* If we are dealing with the menu bar */
3395 /* and this is a click on an already "popped" item: */
3396 /* Stop the menu tracking and close the opened submenus */
3397 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3402 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3404 PtMenu
->TimeToHide
= TRUE
;
3410 /***********************************************************************
3413 * Walks menu chain trying to find a menu pt maps to.
3415 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3420 if (!menu
) return NULL
;
3422 /* try subpopup first (if any) */
3423 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3425 pItem
= menu
->rgItems
;
3426 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3427 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3429 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3433 /* check the current window (avoiding WM_HITTEST) */
3436 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3437 INT ht
= GetNCHitEx(pWnd
, pt
);
3438 if ( menu
->fFlags
& MNF_POPUP
)
3440 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3442 else if (ht
== HTSYSMENU
)
3443 ret
= get_win_sys_menu(menu
->hWnd
);
3444 else if (ht
== HTMENU
)
3445 ret
= IntGetMenu( menu
->hWnd
);
3450 /***********************************************************************
3453 * Return TRUE if we can go on with menu tracking.
3455 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3457 UINT Index
= NO_SELECTED_ITEM
;
3461 if (IS_SYSTEM_MENU(PtMenu
))
3464 //// ReactOS only HACK: CORE-2338
3465 // Windows tracks mouse moves to the system menu but does not open it.
3466 // Only keyboard tracking can do that.
3468 TRACE("SystemMenu\n");
3469 return TRUE
; // Stay inside the Loop!
3472 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3475 if (Index
== NO_SELECTED_ITEM
)
3477 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3479 else if (PtMenu
->iItem
!= Index
)
3481 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3482 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3487 /***********************************************************************
3490 * Return the handle of the selected sub-popup menu (if any).
3492 static PMENU
MENU_GetSubPopup( PMENU menu
)
3496 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3498 item
= &menu
->rgItems
[menu
->iItem
];
3499 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3501 return item
->spSubMenu
;
3506 /***********************************************************************
3509 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3511 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3515 /* When skipping left, we need to do something special after the
3517 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3521 /* When skipping right, for the non-system menu, we need to
3522 handle the last non-special menu item (ie skip any window
3523 icons such as MDI maximize, restore or close) */
3524 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3526 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3527 while (i
< pmt
->TopMenu
->cItems
) {
3528 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3529 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3533 if (i
== pmt
->TopMenu
->cItems
) {
3537 /* When skipping right, we need to cater for the system menu */
3538 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3540 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3547 MDINEXTMENU NextMenu
;
3554 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3555 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3556 NextMenu
.hmenuNext
= NULL
;
3557 NextMenu
.hwndNext
= NULL
;
3558 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3560 TRACE("%p [%p] -> %p [%p]\n",
3561 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3563 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3565 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3566 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3568 /* switch to the menu bar */
3570 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3574 Id
= MenuTmp
->cItems
- 1;
3576 /* Skip backwards over any system predefined icons,
3577 eg. MDI close, restore etc icons */
3579 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3580 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3583 hNewMenu
= UserHMGetHandle(MenuTmp
);
3585 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3587 /* switch to the system menu */
3588 MenuTmp
= get_win_sys_menu(hNewWnd
);
3589 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3594 else /* application returned a new menu to switch to */
3596 hNewMenu
= NextMenu
.hmenuNext
;
3597 hNewWnd
= NextMenu
.hwndNext
;
3599 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3601 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3603 /* get the real system menu */
3604 MenuTmp
= get_win_sys_menu(hNewWnd
);
3605 hNewMenu
= UserHMGetHandle(MenuTmp
);
3607 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3609 /* FIXME: Not sure what to do here;
3610 * perhaps try to track NewMenu as a popup? */
3612 WARN(" -- got confused.\n");
3619 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3621 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3623 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3624 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3627 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3629 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3630 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3631 ///// Use thread pms!!!!
3632 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3633 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3634 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3635 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3638 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3639 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3646 /***********************************************************************
3649 * The idea is not to show the popup if the next input message is
3650 * going to hide it anyway.
3652 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3656 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3658 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3659 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3664 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3665 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3667 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3668 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3669 if( msg
.message
== WM_KEYDOWN
&&
3670 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3672 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3678 /* failures go through this */
3679 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3683 /***********************************************************************
3686 * Handle a VK_ESCAPE key event in a menu.
3688 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3690 BOOL EndMenu
= TRUE
;
3692 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3694 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3696 PMENU MenuPrev
, MenuTmp
;
3698 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3700 /* close topmost popup */
3701 while (MenuTmp
!= pmt
->CurrentMenu
)
3704 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3707 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3708 pmt
->CurrentMenu
= MenuPrev
;
3716 /***********************************************************************
3719 * Handle a VK_LEFT key event in a menu.
3721 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
)
3723 PMENU MenuTmp
, MenuPrev
;
3726 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3728 /* Try to move 1 column left (if possible) */
3729 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3731 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3735 /* close topmost popup */
3736 while (MenuTmp
!= pmt
->CurrentMenu
)
3739 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3742 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3743 pmt
->CurrentMenu
= MenuPrev
;
3745 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3747 /* move menu bar selection if no more popups are left */
3749 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3750 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3752 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3754 /* A sublevel menu was displayed - display the next one
3755 * unless there is another displacement coming up */
3757 if (!MENU_SuspendPopup(pmt
, WM_KEYDOWN
))
3758 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3764 /***********************************************************************
3767 * Handle a VK_RIGHT key event in a menu.
3769 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
)
3774 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3775 pmt
->CurrentMenu
, pmt
->TopMenu
);
3777 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3779 /* If already displaying a popup, try to display sub-popup */
3781 menutmp
= pmt
->CurrentMenu
;
3782 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3784 /* if subpopup was displayed then we are done */
3785 if (menutmp
!= pmt
->CurrentMenu
) return;
3788 /* Check to see if there's another column */
3789 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3791 TRACE("Going to %d.\n", NextCol
);
3792 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3796 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3798 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3800 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3801 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3808 /* try to move to the next item */
3809 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3810 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3812 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3814 if ( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
3815 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3820 /***********************************************************************
3823 * Menu tracking code.
3825 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3826 PWND pwnd
, const RECT
*lprect
)
3830 INT executedMenuId
= -1;
3834 BOOL enterIdleSent
= FALSE
;
3835 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3837 if (pti
!= pwnd
->head
.pti
)
3839 ERR("Not the same PTI!!!!\n");
3843 mt
.CurrentMenu
= pmenu
;
3849 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3850 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3851 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3853 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3855 if (wFlags
& TPM_BUTTONDOWN
)
3857 /* Get the result in order to start the tracking or not */
3858 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3859 fInsideMenuLoop
= fRemove
;
3862 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3864 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3866 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3867 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3868 co_UserSetCapture(NULL
); /* release the capture */
3872 capture_win
= IntGetCapture();
3874 while (fInsideMenuLoop
)
3876 BOOL ErrorExit
= FALSE
;
3877 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3880 /* we have to keep the message in the queue until it's
3881 * clear that menu loop is not over yet. */
3885 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3887 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3888 /* remove the message from the queue */
3889 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3893 /* ReactOS Checks */
3894 if (!VerifyWnd(mt
.OwnerWnd
) ||
3895 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3896 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3897 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3899 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3905 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3906 enterIdleSent
= TRUE
;
3907 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3909 co_IntWaitMessage(NULL
, 0, 0);
3913 if (ErrorExit
) break; // Gracefully dropout.
3915 /* check if EndMenu() tried to cancel us, by posting this message */
3916 if (msg
.message
== WM_CANCELMODE
)
3918 /* we are now out of the loop */
3919 fInsideMenuLoop
= FALSE
;
3921 /* remove the message from the queue */
3922 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3924 /* break out of internal loop, ala ESCAPE */
3928 IntTranslateKbdMessage(&msg
, 0);
3931 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
3932 enterIdleSent
=FALSE
;
3935 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3938 * Use the mouse coordinates in lParam instead of those in the MSG
3939 * struct to properly handle synthetic messages. They are already
3940 * in screen coordinates.
3942 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3943 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3945 /* Find a menu for this mouse event */
3946 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
3950 /* no WM_NC... messages in captured state */
3952 case WM_RBUTTONDBLCLK
:
3953 case WM_RBUTTONDOWN
:
3954 if (!(wFlags
& TPM_RIGHTBUTTON
))
3956 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3960 case WM_LBUTTONDBLCLK
:
3961 case WM_LBUTTONDOWN
:
3962 /* If the message belongs to the menu, removes it from the queue */
3963 /* Else, end menu tracking */
3964 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
3965 fInsideMenuLoop
= fRemove
;
3966 if ( msg
.message
== WM_LBUTTONDBLCLK
||
3967 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
3971 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3974 /* Check if a menu was selected by the mouse */
3977 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
3979 /* End the loop if executedMenuId is an item ID */
3980 /* or if the job was done (executedMenuId = 0). */
3981 fRemove
= (executedMenuId
!= -1);
3982 fInsideMenuLoop
= !fRemove
;
3984 /* No menu was selected by the mouse */
3985 /* if the function was called by TrackPopupMenu, continue
3986 with the menu tracking. If not, stop it */
3988 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
3993 /* the selected menu item must be changed every time */
3994 /* the mouse moves. */
3997 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
3999 } /* switch(msg.message) - mouse */
4001 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4003 fRemove
= TRUE
; /* Keyboard messages are always removed */
4012 fInsideMenuLoop
= FALSE
;
4017 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4018 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4022 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4023 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4024 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4025 else /* otherwise try to move selection */
4026 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4030 MENU_KeyLeft( &mt
, wFlags
);
4034 MENU_KeyRight( &mt
, wFlags
);
4038 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4044 hi
.cbSize
= sizeof(HELPINFO
);
4045 hi
.iContextType
= HELPINFO_MENUITEM
;
4046 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4049 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4050 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4051 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4052 hi
.MousePos
= msg
.pt
;
4053 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4060 break; /* WM_KEYDOWN */
4068 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4070 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4071 fEndMenu
= (executedMenuId
!= -2);
4072 fInsideMenuLoop
= !fEndMenu
;
4076 /* Hack to avoid control chars. */
4077 /* We will find a better way real soon... */
4078 if (msg
.wParam
< 32) break;
4080 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4082 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4083 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4086 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4087 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4088 fEndMenu
= (executedMenuId
!= -2);
4089 fInsideMenuLoop
= !fEndMenu
;
4093 } /* switch(msg.message) - kbd */
4097 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4098 IntDispatchMessage( &msg
);
4102 if (fInsideMenuLoop
) fRemove
= TRUE
;
4104 /* finally remove message from the queue */
4106 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4107 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4108 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4111 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4112 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4113 co_UserSetCapture(NULL
); /* release the capture */
4115 /* If dropdown is still painted and the close box is clicked on
4116 then the menu will be destroyed as part of the DispatchMessage above.
4117 This will then invalidate the menu handle in mt.hTopMenu. We should
4118 check for this first. */
4119 if ( VerifyMenu( mt
.TopMenu
) )
4121 if (VerifyWnd(mt
.OwnerWnd
))
4123 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4125 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4127 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4130 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4132 co_UserDestroyWindow(pwndTM
);
4134 mt
.TopMenu
->hWnd
= NULL
;
4136 if (!(wFlags
& TPM_NONOTIFY
))
4138 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4139 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4142 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4143 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4146 /* Reset the variable for hiding menu */
4147 mt
.TopMenu
->TimeToHide
= FALSE
;
4150 /* The return value is only used by TrackPopupMenu */
4151 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4152 if (executedMenuId
== -1) executedMenuId
= 0;
4153 return executedMenuId
;
4156 /***********************************************************************
4159 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4162 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4164 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4166 co_UserHideCaret(0);
4168 /* This makes the menus of applications built with Delphi work.
4169 * It also enables menus to be displayed in more than one window,
4170 * but there are some bugs left that need to be fixed in this case.
4174 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4178 top_popup
= Menu
->hWnd
;
4179 top_popup_hmenu
= UserHMGetHandle(Menu
);
4182 fInsideMenuLoop
= TRUE
;
4185 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4186 if (!(wFlags
& TPM_NONOTIFY
))
4188 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4192 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4194 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4195 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4196 co_UserSetCapture(capture_win
); // 2
4197 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4199 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4201 if (!(wFlags
& TPM_NONOTIFY
))
4203 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4204 /* If an app changed/recreated menu bar entries in WM_INITMENU
4205 * menu sizes will be recalculated once the menu created/shown.
4209 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4211 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4216 /***********************************************************************
4219 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4221 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4223 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4225 if (!(wFlags
& TPM_NONOTIFY
))
4226 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4228 co_UserShowCaret(0);
4231 top_popup_hmenu
= NULL
;
4236 /***********************************************************************
4237 * MenuTrackMouseMenuBar
4239 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4241 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4243 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) );
4244 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4246 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4248 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4249 if (VerifyMenu(pMenu
))
4251 /* map point to parent client coordinates */
4252 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4253 if (Parent
!= UserGetDesktopWindow())
4255 IntScreenToClient(Parent
, &pt
);
4258 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4259 /* fetch the window menu again, it may have changed */
4260 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4261 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4262 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4266 /***********************************************************************
4267 * MenuTrackKbdMenuBar
4269 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4271 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4273 UINT uItem
= NO_SELECTED_ITEM
;
4275 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4277 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4279 /* find window that has a menu */
4281 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4282 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4284 /* check if we have to track a system menu */
4286 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4287 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4289 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4290 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4292 wParam
|= HTSYSMENU
; /* prevent item lookup */
4295 if (!VerifyMenu( TrackMenu
)) return;
4297 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4299 /* fetch the window menu again, it may have changed */
4300 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4302 if( wChar
&& wChar
!= ' ' )
4304 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4305 if ( uItem
>= (UINT
)(-2) )
4307 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4308 /* schedule end of menu tracking */
4309 wFlags
|= TF_ENDMENU
;
4314 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4316 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4318 if( uItem
== NO_SELECTED_ITEM
)
4319 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4321 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4325 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4326 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4329 /**********************************************************************
4330 * TrackPopupMenuEx (USER32.@)
4332 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4333 PWND pWnd
, LPTPMPARAMS lpTpm
)
4336 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4338 if (pti
!= pWnd
->head
.pti
)
4340 ERR("Must be the same pti!\n");
4344 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4345 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4346 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4348 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4350 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4354 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4356 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4358 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4359 if (!(wFlags
& TPM_NONOTIFY
))
4361 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4364 if (menu
->fFlags
& MNF_SYSMENU
)
4365 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4367 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
, x
, y
, 0, 0 ))
4368 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4369 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4372 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4373 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4374 co_UserSetCapture(NULL
); /* release the capture */
4378 // HACK : Until back trace fault in co_IntUpdateWindows and MENU_TrackMenu.
4380 if (EngGetLastError() == ERROR_ACCESS_DENIED
)
4382 EngSetLastError(NO_ERROR
);
4385 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4389 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4390 if (pwndM
) // wine hack around this with their destroy function.
4391 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4394 if (!(wFlags
& TPM_NONOTIFY
))
4396 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4397 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4415 PPOPUPMENU pPopupMenu
;
4419 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4425 if (Message
!= WM_NCCREATE
)
4427 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4430 Wnd
->fnid
= FNID_MENU
;
4431 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4432 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4433 pPopupMenu
->spwndPopupMenu
= Wnd
;
4434 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4435 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4441 if (Wnd
->fnid
!= FNID_MENU
)
4443 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4446 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4454 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4455 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4459 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4460 *lResult
= MA_NOACTIVATE
;
4466 IntBeginPaint(Wnd
, &ps
);
4467 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4468 IntEndPaint(Wnd
, &ps
);
4472 case WM_PRINTCLIENT
:
4474 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4483 /* zero out global pointer in case resident popup window was destroyed. */
4486 if (UserHMGetHandle(Wnd
) == top_popup
)
4489 top_popup_hmenu
= NULL
;
4494 ERR("No Window Pop Up!\n");
4500 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4501 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4502 Wnd
->fnid
= FNID_DESTROY
;
4506 case MM_SETMENUHANDLE
: // wine'isms
4509 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4512 ERR("Bad Menu Handle\n");
4515 pPopupMenu
->spmenu
= pmenu
;
4519 case MM_GETMENUHANDLE
: // wine'isms
4521 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4525 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4527 ERR("Someone is passing unknown menu messages %d\n",Message
);
4529 TRACE("PMWP to IDWP %d\n",Message
);
4530 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4538 IntHiliteMenuItem(PWND WindowObject
,
4544 UINT uItem
= uItemHilite
;
4546 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4548 if (uHilite
& MF_HILITE
)
4550 MenuItem
->fState
|= MF_HILITE
;
4554 MenuItem
->fState
&= ~MF_HILITE
;
4556 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4557 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4558 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4560 return TRUE
; // Always returns true!!!!
4564 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4568 DWORD dwExStyle
= 0;
4569 BOOLEAN retValue
= TRUE
;
4571 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4573 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4575 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4577 dwStyle
= pWindowObject
->style
;
4578 dwExStyle
= pWindowObject
->ExStyle
;
4580 bti
->rcTitleBar
.top
= 0;
4581 bti
->rcTitleBar
.left
= 0;
4582 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4583 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4585 /* Is it iconiced ? */
4586 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4588 /* Remove frame from rectangle */
4589 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4591 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4592 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4594 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4596 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4597 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4599 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4601 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4602 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4605 /* We have additional border information if the window
4606 * is a child (but not an MDI child) */
4607 if ( (dwStyle
& WS_CHILD
) &&
4608 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4610 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4612 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4613 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4616 if (dwExStyle
& WS_EX_STATICEDGE
)
4618 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4619 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4624 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4625 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4626 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4628 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4629 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4631 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4632 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4636 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4637 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4638 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4641 if (dwStyle
& WS_CAPTION
)
4643 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4644 if (dwStyle
& WS_SYSMENU
)
4646 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4648 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4649 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4653 if (!(dwStyle
& WS_MINIMIZEBOX
))
4655 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4657 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4659 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4663 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4665 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4667 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4669 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4674 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4675 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4676 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4677 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4682 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4687 EngSetLastError(ERROR_INVALID_PARAMETER
);
4699 LPCMENUITEMINFOW UnsafeItemInfo
,
4700 PUNICODE_STRING lpstr
)
4703 ROSMENUITEMINFO ItemInfo
;
4705 /* Try to copy the whole MENUITEMINFOW structure */
4706 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4707 if (NT_SUCCESS(Status
))
4709 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4710 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4712 EngSetLastError(ERROR_INVALID_PARAMETER
);
4715 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4718 /* Try to copy without last field (not present in older versions) */
4719 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4720 if (NT_SUCCESS(Status
))
4722 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4724 EngSetLastError(ERROR_INVALID_PARAMETER
);
4727 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4728 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4731 SetLastNtError(Status
);
4735 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4740 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4745 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4747 if (pItem
->spSubMenu
)
4749 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4752 return (pItem
->fType
| pItem
->fState
);
4755 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4760 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4765 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4767 if (pItem
->spSubMenu
)
4769 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4775 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4777 PMENU menu
, pSubTarget
;
4779 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4780 return NO_SELECTED_ITEM
;
4782 pSubTarget
= UserGetMenuObject(hSubTarget
);
4784 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4786 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4792 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4794 PWINSTATION_OBJECT WinStaObject
;
4798 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4800 if (gpepCSRSS
!= CurrentProcess
)
4803 * gpepCSRSS does not have a Win32WindowStation
4806 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4812 if (!NT_SUCCESS(Status
))
4814 ERR("Validation of window station handle (%p) failed\n",
4815 CurrentProcess
->Win32WindowStation
);
4816 SetLastNtError(Status
);
4819 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4820 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4822 ERR("Desktop Window Station does not match Process one!\n");
4824 ObDereferenceObject(WinStaObject
);
4828 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4831 if (Menu
) UserDereferenceObject(Menu
);
4832 return (HMENU
)Handle
;
4840 PROSMENUITEMINFO ItemInfo
,
4842 PUNICODE_STRING lpstr
)
4847 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4849 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4854 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4858 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4868 PROSMENUITEMINFO UnsafeItemInfo
,
4870 PUNICODE_STRING lpstr
)
4873 ROSMENUITEMINFO ItemInfo
;
4878 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4879 if (! NT_SUCCESS(Status
))
4881 SetLastNtError(Status
);
4884 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4885 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4886 Size
!= sizeof(ROSMENUITEMINFO
) )
4888 EngSetLastError(ERROR_INVALID_PARAMETER
);
4891 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4892 if (! NT_SUCCESS(Status
))
4894 SetLastNtError(Status
);
4897 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4899 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4900 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4902 EngSetLastError(ERROR_INVALID_PARAMETER
);
4906 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4908 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
4909 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
4912 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4918 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
4922 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
4925 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
4926 if (! NT_SUCCESS(Status
))
4928 SetLastNtError(Status
);
4940 PROSMENUINFO UnsafeMenuInfo
,
4946 ROSMENUINFO MenuInfo
;
4948 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
4949 if (! NT_SUCCESS(Status
))
4951 SetLastNtError(Status
);
4954 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
4956 EngSetLastError(ERROR_INVALID_PARAMETER
);
4959 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
4960 if (! NT_SUCCESS(Status
))
4962 SetLastNtError(Status
);
4969 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
4974 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
4977 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
4978 if (! NT_SUCCESS(Status
))
4980 SetLastNtError(Status
);
5000 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5002 Rect
->left
= MenuItem
->xItem
;
5003 Rect
->top
= MenuItem
->yItem
;
5004 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5005 Rect
->bottom
= MenuItem
->cyItem
;
5009 ERR("Failed Item Lookup! %u\n", uItem
);
5015 HWND hWnd
= Menu
->hWnd
;
5016 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5019 if (Menu
->fFlags
& MNF_POPUP
)
5021 XMove
= pWnd
->rcClient
.left
;
5022 YMove
= pWnd
->rcClient
.top
;
5026 XMove
= pWnd
->rcWindow
.left
;
5027 YMove
= pWnd
->rcWindow
.top
;
5030 Rect
->left
+= XMove
;
5032 Rect
->right
+= XMove
;
5033 Rect
->bottom
+= YMove
;
5038 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5040 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5041 HMENU hSysMenu
, hNewMenu
= NULL
;
5042 ROSMENUITEMINFO ItemInfoSet
= {0};
5043 ROSMENUITEMINFO ItemInfo
= {0};
5044 UNICODE_STRING MenuName
;
5046 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5047 if (NULL
== hSysMenu
)
5051 SysMenu
= UserGetMenuObject(hSysMenu
);
5052 if (NULL
== SysMenu
)
5054 UserDestroyMenu(hSysMenu
);
5058 SysMenu
->fFlags
|= MNF_SYSMENU
;
5059 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5063 //hNewMenu = co_IntLoadSysMenuTemplate();
5064 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5066 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5067 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5071 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5072 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5073 //ERR("%wZ\n",&MenuName);
5078 IntReleaseMenuObject(SysMenu
);
5079 UserDestroyMenu(hSysMenu
);
5082 Menu
= UserGetMenuObject(hNewMenu
);
5085 IntReleaseMenuObject(SysMenu
);
5086 UserDestroyMenu(hSysMenu
);
5090 // Do the rest in here.
5092 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5094 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5095 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5096 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5097 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5098 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5099 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5100 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5101 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5102 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5103 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5105 NewMenu
= IntCloneMenu(Menu
);
5107 IntReleaseMenuObject(NewMenu
);
5108 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5110 IntDestroyMenuObject(Menu
, FALSE
);
5118 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5120 if (Window
->pcls
->style
& CS_NOCLOSE
)
5121 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5123 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5124 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5125 ItemInfo
.fType
= MF_POPUP
;
5126 ItemInfo
.fState
= MFS_ENABLED
;
5127 ItemInfo
.dwTypeData
= NULL
;
5129 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5130 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5134 ERR("failed to load system menu!\n");
5139 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5145 if (Window
->SystemMenu
)
5147 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5148 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5150 IntDestroyMenuObject(Menu
, TRUE
);
5151 Window
->SystemMenu
= NULL
;
5157 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5158 if ((!Window
->SystemMenu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5160 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5161 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5165 if (Window
->SystemMenu
)
5167 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5168 /* Store the dummy sysmenu handle to facilitate the refresh */
5169 /* of the close button if the SC_CLOSE item change */
5170 Menu
= UserGetMenuObject(hMenu
);
5173 Menu
->spwndNotify
= Window
;
5174 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5182 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5186 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5188 if (Window
->SystemMenu
)
5190 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5193 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5194 IntDestroyMenuObject(OldMenu
, TRUE
);
5198 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5200 { // Use spmenuSys too!
5201 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5204 Window
->SystemMenu
= NULL
;
5206 if (Menu
&& Window
!= Menu
->spwndNotify
)
5208 Menu
->spwndNotify
= Window
;
5220 PMENU OldMenu
, NewMenu
= NULL
;
5222 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5224 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5225 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5229 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5237 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5238 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5247 NewMenu
= IntGetMenuObject(Menu
);
5248 if (NULL
== NewMenu
)
5250 if (NULL
!= OldMenu
)
5252 IntReleaseMenuObject(OldMenu
);
5254 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5257 if (NULL
!= NewMenu
->hWnd
)
5259 /* Can't use the same menu for two windows */
5260 if (NULL
!= OldMenu
)
5262 IntReleaseMenuObject(OldMenu
);
5264 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5270 Wnd
->IDMenu
= (UINT
) Menu
;
5271 if (NULL
!= NewMenu
)
5273 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5274 IntReleaseMenuObject(NewMenu
);
5276 if (NULL
!= OldMenu
)
5278 OldMenu
->hWnd
= NULL
;
5279 IntReleaseMenuObject(OldMenu
);
5286 /* FUNCTIONS *****************************************************************/
5291 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5306 UserEnterExclusive();
5308 if(!(Window
= UserGetWindowObject(hwnd
)))
5310 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5315 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5322 Rect
.left
= leftBorder
;
5323 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5327 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5329 UserReleaseDC( 0, hdc
, FALSE
);
5340 NtUserCheckMenuItem(
5346 DECLARE_RETURN(DWORD
);
5348 TRACE("Enter NtUserCheckMenuItem\n");
5349 UserEnterExclusive();
5351 if(!(Menu
= UserGetMenuObject(hMenu
)))
5356 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5359 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5374 DECLARE_RETURN(BOOL
);
5376 TRACE("Enter NtUserDeleteMenu\n");
5377 UserEnterExclusive();
5379 if(!(Menu
= UserGetMenuObject(hMenu
)))
5384 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5387 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5393 * NtUserGetSystemMenu
5395 * The NtUserGetSystemMenu function allows the application to access the
5396 * window menu (also known as the system menu or the control menu) for
5397 * copying and modifying.
5401 * Handle to the window that will own a copy of the window menu.
5403 * Specifies the action to be taken. If this parameter is FALSE,
5404 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5405 * currently in use. The copy is initially identical to the window menu
5406 * but it can be modified.
5407 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5408 * to the default state. The previous window menu, if any, is destroyed.
5411 * If the bRevert parameter is FALSE, the return value is a handle to a
5412 * copy of the window menu. If the bRevert parameter is TRUE, the return
5420 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5424 DECLARE_RETURN(HMENU
);
5426 TRACE("Enter NtUserGetSystemMenu\n");
5429 if (!(Window
= UserGetWindowObject(hWnd
)))
5434 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5439 RETURN(Menu
->head
.h
);
5442 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5448 * NtUserSetSystemMenu
5455 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5457 BOOL Result
= FALSE
;
5460 DECLARE_RETURN(BOOL
);
5462 TRACE("Enter NtUserSetSystemMenu\n");
5463 UserEnterExclusive();
5465 if (!(Window
= UserGetWindowObject(hWnd
)))
5473 * Assign new menu handle and Up the Lock Count.
5475 if (!(Menu
= IntGetMenuObject(hMenu
)))
5480 Result
= IntSetSystemMenu(Window
, Menu
);
5483 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5488 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5497 NtUserGetTitleBarInfo(
5502 TITLEBARINFO bartitleinfo
;
5503 DECLARE_RETURN(BOOLEAN
);
5504 BOOLEAN retValue
= TRUE
;
5506 TRACE("Enter NtUserGetTitleBarInfo\n");
5507 UserEnterExclusive();
5509 /* Vaildate the windows handle */
5510 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5512 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5518 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5519 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5520 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5522 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5524 /* Fail copy the data */
5525 EngSetLastError(ERROR_INVALID_PARAMETER
);
5530 /* Get the tile bar info */
5533 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5538 /* Copy our buffer to user mode buffer bti */
5539 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5540 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5544 /* Fail copy the data */
5545 EngSetLastError(ERROR_INVALID_PARAMETER
);
5555 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5563 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5566 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5568 if(!(Menu
= UserGetMenuObject(hMenu
)))
5573 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5575 EngSetLastError(ERROR_ACCESS_DENIED
);
5578 return IntDestroyMenuObject(Menu
, FALSE
);
5589 DECLARE_RETURN(BOOL
);
5591 TRACE("Enter NtUserDestroyMenu\n");
5592 UserEnterExclusive();
5594 if(!(Menu
= UserGetMenuObject(hMenu
)))
5598 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5600 EngSetLastError(ERROR_ACCESS_DENIED
);
5603 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5606 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5615 NtUserEnableMenuItem(
5621 DECLARE_RETURN(UINT
);
5623 TRACE("Enter NtUserEnableMenuItem\n");
5624 UserEnterExclusive();
5626 if(!(Menu
= UserGetMenuObject(hMenu
)))
5631 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5634 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5646 TRACE("Enter NtUserEndMenu\n");
5647 UserEnterExclusive();
5648 /* if ( gptiCurrent->pMenuState &&
5649 gptiCurrent->pMenuState->pGlobalPopupMenu )
5651 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5654 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5657 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5659 if (fInsideMenuLoop
&& top_popup
)
5661 fInsideMenuLoop
= FALSE
;
5662 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5665 TRACE("Leave NtUserEndMenu\n");
5673 NtUserGetMenuBarInfo(
5683 PPOPUPMENU pPopupMenu
;
5684 USER_REFERENCE_ENTRY Ref
;
5685 NTSTATUS Status
= STATUS_SUCCESS
;
5687 DECLARE_RETURN(BOOL
);
5689 TRACE("Enter NtUserGetMenuBarInfo\n");
5692 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5694 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5698 UserRefObjectCo(pWnd
, &Ref
);
5700 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5702 kmbi
.hwndMenu
= NULL
;
5703 kmbi
.fBarFocused
= FALSE
;
5704 kmbi
.fFocused
= FALSE
;
5709 if (!pWnd
->pcls
->fnid
)
5711 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5713 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5714 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5717 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5718 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5719 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5720 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5722 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5724 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5729 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5730 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5731 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5734 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5735 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5736 hMenu
= UserHMGetHandle(Menu
);
5747 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5748 kmbi
.cbSize
= pmbi
->cbSize
;
5750 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5756 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5758 EngSetLastError(ERROR_INVALID_PARAMETER
);
5762 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5766 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5771 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5772 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5773 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5774 TRACE("idItem a 0 %d\n",Ret
);
5778 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5779 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5783 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5784 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5787 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5788 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5790 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5795 kmbi
.fFocused
= kmbi
.fBarFocused
;
5800 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5801 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5803 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5805 Status
= _SEH2_GetExceptionCode();
5809 if (!NT_SUCCESS(Status
))
5811 SetLastNtError(Status
);
5818 if (pWnd
) UserDerefObjectCo(pWnd
);
5819 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5832 PMENU Menu
, SubMenu
;
5835 DECLARE_RETURN(UINT
);
5837 TRACE("Enter NtUserGetMenuIndex\n");
5840 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5841 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5844 MenuItem
= Menu
->rgItems
;
5845 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5847 if (MenuItem
->spSubMenu
== SubMenu
)
5848 RETURN(MenuItem
->wID
);
5853 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5862 NtUserGetMenuItemRect(
5873 NTSTATUS Status
= STATUS_SUCCESS
;
5874 DECLARE_RETURN(BOOL
);
5876 TRACE("Enter NtUserGetMenuItemRect\n");
5879 if (!(Menu
= UserGetMenuObject(hMenu
)))
5884 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5886 Rect
.left
= MenuItem
->xItem
;
5887 Rect
.top
= MenuItem
->yItem
;
5888 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5889 Rect
.bottom
= MenuItem
->cyItem
;
5899 if (lprcItem
== NULL
) RETURN( FALSE
);
5901 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
5903 if (Menu
->fFlags
& MNF_POPUP
)
5905 XMove
= ReferenceWnd
->rcClient
.left
;
5906 YMove
= ReferenceWnd
->rcClient
.top
;
5910 XMove
= ReferenceWnd
->rcWindow
.left
;
5911 YMove
= ReferenceWnd
->rcWindow
.top
;
5916 Rect
.right
+= XMove
;
5917 Rect
.bottom
+= YMove
;
5921 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
5923 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5925 Status
= _SEH2_GetExceptionCode();
5929 if (!NT_SUCCESS(Status
))
5931 SetLastNtError(Status
);
5937 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
5946 NtUserHiliteMenuItem(
5954 DECLARE_RETURN(BOOLEAN
);
5956 TRACE("Enter NtUserHiliteMenuItem\n");
5957 UserEnterExclusive();
5959 if(!(Window
= UserGetWindowObject(hWnd
)))
5961 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5965 if(!(Menu
= UserGetMenuObject(hMenu
)))
5967 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5971 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
5974 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
5984 NtUserDrawMenuBarTemp(
5994 NTSTATUS Status
= STATUS_SUCCESS
;
5995 DECLARE_RETURN(DWORD
);
5997 ERR("Enter NtUserDrawMenuBarTemp\n");
5998 UserEnterExclusive();
6000 if(!(Window
= UserGetWindowObject(hWnd
)))
6002 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6006 if(!(Menu
= UserGetMenuObject(hMenu
)))
6008 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6014 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6015 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6017 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6019 Status
= _SEH2_GetExceptionCode();
6023 if (Status
!= STATUS_SUCCESS
)
6025 SetLastNtError(Status
);
6029 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6032 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6041 NtUserMenuItemFromPoint(
6051 DECLARE_RETURN(int);
6053 TRACE("Enter NtUserMenuItemFromPoint\n");
6054 UserEnterExclusive();
6056 if (!(Menu
= UserGetMenuObject(hMenu
)))
6061 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6066 X
-= Window
->rcWindow
.left
;
6067 Y
-= Window
->rcWindow
.top
;
6070 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6074 Rect
.left
= mi
->xItem
;
6075 Rect
.top
= mi
->yItem
;
6076 Rect
.right
= mi
->cxItem
;
6077 Rect
.bottom
= mi
->cyItem
;
6079 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6081 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6087 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6090 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6110 UserEnterExclusive();
6112 if(!(Window
= UserGetWindowObject(hWnd
)))
6114 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6119 Rect
.left
= leftBorder
;
6120 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6124 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6141 DECLARE_RETURN(BOOL
);
6143 TRACE("Enter NtUserRemoveMenu\n");
6144 UserEnterExclusive();
6146 if(!(Menu
= UserGetMenuObject(hMenu
)))
6151 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6154 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6171 DECLARE_RETURN(BOOL
);
6173 TRACE("Enter NtUserSetMenu\n");
6174 UserEnterExclusive();
6176 if (!(Window
= UserGetWindowObject(hWnd
)))
6181 if (!IntSetMenu(Window
, Menu
, &Changed
))
6186 // Not minimized and please repaint!!!
6187 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6189 USER_REFERENCE_ENTRY Ref
;
6190 UserRefObjectCo(Window
, &Ref
);
6191 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6192 UserDerefObjectCo(Window
);
6198 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6207 NtUserSetMenuContextHelpId(
6209 DWORD dwContextHelpId
)
6212 DECLARE_RETURN(BOOL
);
6214 TRACE("Enter NtUserSetMenuContextHelpId\n");
6215 UserEnterExclusive();
6217 if(!(Menu
= UserGetMenuObject(hMenu
)))
6222 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6225 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6234 NtUserSetMenuDefaultItem(
6240 DECLARE_RETURN(BOOL
);
6242 TRACE("Enter NtUserSetMenuDefaultItem\n");
6243 UserEnterExclusive();
6245 if(!(Menu
= UserGetMenuObject(hMenu
)))
6250 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6253 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6262 NtUserSetMenuFlagRtoL(
6266 DECLARE_RETURN(BOOL
);
6268 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6269 UserEnterExclusive();
6271 if(!(Menu
= UserGetMenuObject(hMenu
)))
6276 RETURN(IntSetMenuFlagRtoL(Menu
));
6279 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6288 NtUserThunkedMenuInfo(
6293 DECLARE_RETURN(BOOL
);
6295 TRACE("Enter NtUserThunkedMenuInfo\n");
6296 UserEnterExclusive();
6298 if (!(Menu
= UserGetMenuObject(hMenu
)))
6303 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6306 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6315 NtUserThunkedMenuItemInfo(
6320 LPMENUITEMINFOW lpmii
,
6321 PUNICODE_STRING lpszCaption
)
6325 UNICODE_STRING lstrCaption
;
6326 DECLARE_RETURN(BOOL
);
6328 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6329 UserEnterExclusive();
6331 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6332 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6334 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6336 if (!(Menu
= UserGetMenuObject(hMenu
)))
6341 /* Check if we got a Caption */
6342 if (lpszCaption
&& lpszCaption
->Buffer
)
6344 /* Copy the string to kernel mode */
6345 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6348 if (!NT_SUCCESS(Status
))
6350 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6351 SetLastNtError(Status
);
6356 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6358 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6361 if (lstrCaption
.Buffer
)
6363 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6366 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6375 NtUserTrackPopupMenuEx(
6387 USER_REFERENCE_ENTRY Ref
;
6389 TRACE("Enter NtUserTrackPopupMenuEx\n");
6390 UserEnterExclusive();
6391 /* Parameter check */
6392 if (!(menu
= UserGetMenuObject( hMenu
)))
6394 ERR("TPME : Invalid Menu handle.\n");
6395 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6399 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6401 ERR("TPME : Invalid Window handle.\n");
6409 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6414 _SEH2_YIELD(goto Exit
);
6418 UserRefObjectCo(pWnd
, &Ref
);
6419 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6420 UserDerefObjectCo(pWnd
);
6423 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);