2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: win32ss/user/ntuser/menu.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
10 DBG_DEFAULT_CHANNEL(UserMenu
);
12 /* INTERNAL ******************************************************************/
14 HFONT ghMenuFont
= NULL
;
15 HFONT ghMenuFontBold
= NULL
;
16 static SIZE MenuCharSize
;
18 /* Use global popup window because there's no way 2 menus can
19 * be tracked at the same time. */
20 static HWND top_popup
= NULL
;
21 static HMENU top_popup_hmenu
= NULL
;
23 BOOL fInsideMenuLoop
= FALSE
;
24 BOOL fInEndMenu
= FALSE
;
26 /* internal popup menu window messages */
28 #define MM_SETMENUHANDLE (WM_USER + 0)
29 #define MM_GETMENUHANDLE (WM_USER + 1)
31 /* internal flags for menu tracking */
33 #define TF_ENDMENU 0x10000
34 #define TF_SUSPENDPOPUP 0x20000
35 #define TF_SKIPREMOVE 0x40000
38 /* maximum allowed depth of any branch in the menu tree.
39 * This value is slightly larger than in windows (25) to
40 * stay on the safe side. */
41 #define MAXMENUDEPTH 30
43 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
45 #define MENUITEMINFO_TYPE_MASK \
46 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
47 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
48 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
50 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
52 #define STATE_MASK (~TYPE_MASK)
54 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
56 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
58 #define IS_SYSTEM_MENU(MenuInfo) \
59 (!((MenuInfo)->fFlags & MNF_POPUP) && ((MenuInfo)->fFlags & MNF_SYSMENU))
61 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
63 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
64 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
66 /* Maximum number of menu items a menu can contain */
67 #define MAX_MENU_ITEMS (0x4000)
68 #define MAX_GOINTOSUBMENU (0x10)
70 /* Space between 2 columns */
71 #define MENU_COL_SPACE 4
73 /* top and bottom margins for popup menus */
74 #define MENU_TOP_MARGIN 3
75 #define MENU_BOTTOM_MARGIN 2
77 #define MENU_ITEM_HBMP_SPACE (5)
78 #define MENU_BAR_ITEMS_SPACE (12)
79 #define SEPARATOR_HEIGHT (5)
80 #define MENU_TAB_SPACE (8)
85 PMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
86 PMENU TopMenu
; /* initial menu */
87 PWND OwnerWnd
; /* where notifications are sent */
91 /* Internal MenuTrackMenu() flags */
92 #define TPM_INTERNAL 0xF0000000
93 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
94 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
99 #define UpdateMenuItemState(state, change) \
101 if((change) & MF_GRAYED) { \
102 (state) |= MF_GRAYED; \
104 (state) &= ~MF_GRAYED; \
105 } /* Separate the two for test_menu_resource_layout.*/ \
106 if((change) & MF_DISABLED) { \
107 (state) |= MF_DISABLED; \
109 (state) &= ~MF_DISABLED; \
111 if((change) & MFS_CHECKED) { \
112 (state) |= MFS_CHECKED; \
114 (state) &= ~MFS_CHECKED; \
116 if((change) & MFS_HILITE) { \
117 (state) |= MFS_HILITE; \
119 (state) &= ~MFS_HILITE; \
121 if((change) & MFS_DEFAULT) { \
122 (state) |= MFS_DEFAULT; \
124 (state) &= ~MFS_DEFAULT; \
126 if((change) & MF_MOUSESELECT) { \
127 (state) |= MF_MOUSESELECT; \
129 (state) &= ~MF_MOUSESELECT; \
135 DumpMenuItemList(PMENU Menu
, PITEM MenuItem
)
137 UINT cnt
= 0, i
= Menu
->cItems
;
140 if(MenuItem
->lpstr
.Length
)
141 DbgPrint(" %d. %wZ\n", ++cnt
, &MenuItem
->lpstr
);
143 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt
, (DWORD
)MenuItem
->lpstr
.Buffer
);
145 if(MFT_BITMAP
& MenuItem
->fType
)
146 DbgPrint("MFT_BITMAP ");
147 if(MFT_MENUBARBREAK
& MenuItem
->fType
)
148 DbgPrint("MFT_MENUBARBREAK ");
149 if(MFT_MENUBREAK
& MenuItem
->fType
)
150 DbgPrint("MFT_MENUBREAK ");
151 if(MFT_OWNERDRAW
& MenuItem
->fType
)
152 DbgPrint("MFT_OWNERDRAW ");
153 if(MFT_RADIOCHECK
& MenuItem
->fType
)
154 DbgPrint("MFT_RADIOCHECK ");
155 if(MFT_RIGHTJUSTIFY
& MenuItem
->fType
)
156 DbgPrint("MFT_RIGHTJUSTIFY ");
157 if(MFT_SEPARATOR
& MenuItem
->fType
)
158 DbgPrint("MFT_SEPARATOR ");
159 if(MFT_STRING
& MenuItem
->fType
)
160 DbgPrint("MFT_STRING ");
161 DbgPrint("\n fState=");
162 if(MFS_DISABLED
& MenuItem
->fState
)
163 DbgPrint("MFS_DISABLED ");
165 DbgPrint("MFS_ENABLED ");
166 if(MFS_CHECKED
& MenuItem
->fState
)
167 DbgPrint("MFS_CHECKED ");
169 DbgPrint("MFS_UNCHECKED ");
170 if(MFS_HILITE
& MenuItem
->fState
)
171 DbgPrint("MFS_HILITE ");
173 DbgPrint("MFS_UNHILITE ");
174 if(MFS_DEFAULT
& MenuItem
->fState
)
175 DbgPrint("MFS_DEFAULT ");
176 if(MFS_GRAYED
& MenuItem
->fState
)
177 DbgPrint("MFS_GRAYED ");
178 DbgPrint("\n wId=%d\n", MenuItem
->wID
);
182 DbgPrint("Entries: %d\n", cnt
);
187 #define FreeMenuText(Menu,MenuItem) \
189 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
190 (MenuItem)->lpstr.Length) { \
191 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
196 IntGetMenuObject(HMENU hMenu
)
198 PMENU Menu
= UserGetMenuObject(hMenu
);
200 Menu
->head
.cLockObj
++;
205 PMENU FASTCALL
VerifyMenu(PMENU pMenu
)
211 if (!pMenu
) return NULL
;
213 Error
= EngGetLastError();
217 hMenu
= UserHMGetHandle(pMenu
);
218 pItem
= pMenu
->rgItems
;
225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
227 ERR("Run away LOOP!\n");
228 EngSetLastError(Error
);
229 _SEH2_YIELD(return NULL
);
233 if ( UserObjectInDestroy(hMenu
))
235 ERR("Menu is marked for destruction!\n");
238 EngSetLastError(Error
);
244 IntIsMenu(HMENU Menu
)
246 if (UserGetMenuObject(Menu
)) return TRUE
;
252 IntGetMenu(HWND hWnd
)
254 PWND Wnd
= ValidateHwndNoErr(hWnd
);
259 return UserGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
262 PMENU
get_win_sys_menu( HWND hwnd
)
265 WND
*win
= ValidateHwndNoErr( hwnd
);
268 ret
= UserGetMenuObject(win
->SystemMenu
);
273 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
)
277 ASSERT(UserIsEnteredExclusive());
278 if (pMenu
->rgItems
) /* recursively destroy submenus */
281 ITEM
*item
= pMenu
->rgItems
;
282 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
284 SubMenu
= item
->spSubMenu
;
285 item
->spSubMenu
= NULL
;
287 /* Remove Item Text */
288 FreeMenuText(pMenu
,item
);
290 /* Remove Item Bitmap and set it for this process */
291 if (item
->hbmp
&& !(item
->fState
& MFS_HBMMENUBMP
))
293 GreSetObjectOwner(item
->hbmp
, GDI_OBJ_HMGR_POWNED
);
297 /* Remove Item submenu */
298 if (bRecurse
&& SubMenu
)//VerifyMenu(SubMenu))
300 /* Release submenu since it was referenced when inserted */
301 IntReleaseMenuObject(SubMenu
);
302 IntDestroyMenuObject(SubMenu
, bRecurse
);
306 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
307 pMenu
->rgItems
= NULL
;
313 /* Callback for the object manager */
315 UserDestroyMenuObject(PVOID Object
)
317 return IntDestroyMenuObject(Object
, TRUE
);
321 IntDestroyMenuObject(PMENU Menu
, BOOL bRecurse
)
323 ASSERT(UserIsEnteredExclusive());
328 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
333 Window
= ValidateHwndNoErr(Menu
->hWnd
);
336 //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
338 /* DestroyMenu should not destroy system menu popup owner */
339 if ((Menu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
)
341 // Should we check it to see if it has Class?
342 ERR("FIXME Pop up menu window thing'ie\n");
343 //co_UserDestroyWindow( Window );
349 if (!UserMarkObjectDestroy(Menu
)) return TRUE
;
351 /* Remove all menu items */
352 IntDestroyMenu( Menu
, bRecurse
);
354 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
355 TRACE("IntDestroyMenuObject %d\n",ret
);
365 NONCLIENTMETRICSW ncm
;
367 /* get the menu font */
368 if (!ghMenuFont
|| !ghMenuFontBold
)
370 ncm
.cbSize
= sizeof(ncm
);
371 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
373 ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
377 ghMenuFont
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
378 if (ghMenuFont
== NULL
)
380 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
383 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
384 ghMenuFontBold
= GreCreateFontIndirectW(&ncm
.lfMenuFont
);
385 if (ghMenuFontBold
== NULL
)
387 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
388 GreDeleteObject(ghMenuFont
);
393 GreSetObjectOwner(ghMenuFont
, GDI_OBJ_HMGR_PUBLIC
);
394 GreSetObjectOwner(ghMenuFontBold
, GDI_OBJ_HMGR_PUBLIC
);
403 /**********************************************************************
406 * detect if there are loops in the menu tree (or the depth is too large)
408 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
414 if (!pmenu
) return depth
;
417 if( depth
> MAXMENUDEPTH
) return depth
;
418 item
= pmenu
->rgItems
;
420 for( i
= 0; i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
422 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
424 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
425 if( bdepth
> subdepth
) subdepth
= bdepth
;
427 if( subdepth
> MAXMENUDEPTH
)
428 TRACE("<- hmenu %p\n", item
->spSubMenu
);
434 /******************************************************************************
436 * UINT MenuGetStartOfNextColumn(
439 *****************************************************************************/
441 static UINT
MENU_GetStartOfNextColumn(
448 return NO_SELECTED_ITEM
;
451 if( i
== NO_SELECTED_ITEM
)
454 pItem
= menu
->rgItems
;
455 if (!pItem
) return NO_SELECTED_ITEM
;
457 for( ; i
< menu
->cItems
; ++i
) {
458 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
462 return NO_SELECTED_ITEM
;
465 /******************************************************************************
467 * UINT MenuGetStartOfPrevColumn(
470 *****************************************************************************/
471 static UINT
MENU_GetStartOfPrevColumn(
478 return NO_SELECTED_ITEM
;
480 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
481 return NO_SELECTED_ITEM
;
483 pItem
= menu
->rgItems
;
484 if (!pItem
) return NO_SELECTED_ITEM
;
486 /* Find the start of the column */
488 for(i
= menu
->iItem
; i
!= 0 &&
489 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
493 return NO_SELECTED_ITEM
;
495 for(--i
; i
!= 0; --i
) {
496 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
500 TRACE("ret %d.\n", i
);
505 /***********************************************************************
508 * Find a menu item. Return a pointer on the item, and modifies *hmenu
509 * in case the item was in a sub-menu.
511 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
514 ITEM
*fallback
= NULL
;
515 UINT fallback_pos
= 0;
518 if (!menu
) return NULL
;
520 if (wFlags
& MF_BYPOSITION
)
522 if (!menu
->cItems
) return NULL
;
523 if (*nPos
>= menu
->cItems
) return NULL
;
524 return &menu
->rgItems
[*nPos
];
528 PITEM item
= menu
->rgItems
;
529 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
533 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
534 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
540 else if (item
->wID
== *nPos
)
542 /* fallback to this item if nothing else found */
547 else if (item
->wID
== *nPos
)
556 *nPos
= fallback_pos
;
561 /***********************************************************************
564 * Find a Sub menu. Return the position of the submenu, and modifies
565 * *hmenu in case it is found in another sub-menu.
566 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
568 static UINT FASTCALL
MENU_FindSubMenu(PMENU
*menu
, PMENU SubTarget
)
573 item
= ((PMENU
)*menu
)->rgItems
;
574 for (i
= 0; i
< ((PMENU
)*menu
)->cItems
; i
++, item
++)
576 if (!item
->spSubMenu
)
580 if (item
->spSubMenu
== SubTarget
)
586 PMENU pSubMenu
= item
->spSubMenu
;
587 UINT pos
= MENU_FindSubMenu( &pSubMenu
, SubTarget
);
588 if (pos
!= NO_SELECTED_ITEM
)
596 return NO_SELECTED_ITEM
;
600 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 newItems
= DesktopHeapReAlloc(pMenu
->head
.rpdesk
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
632 pMenu
->rgItems
= newItems
;
638 /**********************************************************************
641 * Insert (allocate) a new item into a menu.
643 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
647 /* Find where to insert new item */
649 if (flags
& MF_BYPOSITION
) {
650 if (pos
> menu
->cItems
)
653 if (!MENU_FindItem( &menu
, &pos
, flags
))
655 if (submenu
) *submenu
= menu
;
656 if (npos
) *npos
= pos
;
661 /* Make sure that MDI system buttons stay on the right side.
662 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
663 * regardless of their id.
666 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
667 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
670 TRACE("inserting at %u flags %x\n", pos
, flags
);
672 /* Create new items array */
674 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
677 WARN("allocation failed\n" );
680 if (menu
->cItems
> 0)
682 /* Copy the old array into the new one */
683 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
684 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
685 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
687 menu
->rgItems
= newItems
;
689 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
690 menu
->cyMenu
= 0; /* force size recalculate */
691 return &newItems
[pos
];
696 _In_ PMENU MenuObject
,
699 PROSMENUITEMINFO ItemInfo
,
700 PUNICODE_STRING lpstr
)
703 PMENU SubMenu
= NULL
;
705 NT_ASSERT(MenuObject
!= NULL
);
707 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
709 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
713 SubMenu
= MenuObject
;
715 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
717 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
719 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
723 /* Force size recalculation! */
725 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
727 TRACE("IntInsertMenuItemToList = %u %i\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
734 _Out_ PHANDLE Handle
,
736 _In_ PDESKTOP Desktop
,
737 _In_ PPROCESSINFO ppi
)
741 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
753 Menu
->cyMax
= 0; /* Default */
754 Menu
->hbrBack
= NULL
; /* No brush */
755 Menu
->dwContextHelpId
= 0; /* Default */
756 Menu
->dwMenuData
= 0; /* Default */
757 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
758 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
759 Menu
->spwndNotify
= NULL
;
760 Menu
->cyMenu
= 0; // Height
761 Menu
->cxMenu
= 0; // Width
762 Menu
->cItems
= 0; // Item count
765 Menu
->cxTextAlign
= 0;
766 Menu
->rgItems
= NULL
;
769 Menu
->TimeToHide
= FALSE
;
775 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
777 PITEM MenuItem
, NewMenuItem
= NULL
;
783 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, Source
->cItems
* sizeof(ITEM
));
784 if(!NewMenuItem
) return FALSE
;
786 RtlZeroMemory(NewMenuItem
, Source
->cItems
* sizeof(ITEM
));
788 Destination
->rgItems
= NewMenuItem
;
790 MenuItem
= Source
->rgItems
;
791 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
793 NewMenuItem
->fType
= MenuItem
->fType
;
794 NewMenuItem
->fState
= MenuItem
->fState
;
795 NewMenuItem
->wID
= MenuItem
->wID
;
796 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
797 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
798 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
799 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
800 if (MenuItem
->lpstr
.Length
)
802 NewMenuItem
->lpstr
.Length
= 0;
803 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
804 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
805 if (!NewMenuItem
->lpstr
.Buffer
)
807 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
810 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
811 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
812 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
816 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
817 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
819 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
820 Destination
->cItems
= i
+ 1;
826 IntCloneMenu(PMENU Source
)
834 /* A menu is valid process wide. We can pass to the object manager any thread ptr */
835 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
837 ((PPROCESSINFO
)Source
->head
.hTaskWow
)->ptiList
,
844 Menu
->fFlags
= Source
->fFlags
;
845 Menu
->cyMax
= Source
->cyMax
;
846 Menu
->hbrBack
= Source
->hbrBack
;
847 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
848 Menu
->dwMenuData
= Source
->dwMenuData
;
849 Menu
->iItem
= NO_SELECTED_ITEM
;
850 Menu
->spwndNotify
= NULL
;
856 Menu
->cxTextAlign
= 0;
857 Menu
->rgItems
= NULL
;
860 Menu
->TimeToHide
= FALSE
;
862 IntCloneMenuItems(Menu
, Source
);
868 IntSetMenuFlagRtoL(PMENU Menu
)
870 ERR("SetMenuFlagRtoL\n");
871 Menu
->fFlags
|= MNF_RTOL
;
876 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
878 Menu
->dwContextHelpId
= dwContextHelpId
;
883 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
885 if(lpmi
->fMask
& MIM_BACKGROUND
)
886 lpmi
->hbrBack
= Menu
->hbrBack
;
887 if(lpmi
->fMask
& MIM_HELPID
)
888 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
889 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
890 lpmi
->cyMax
= Menu
->cyMax
;
891 if(lpmi
->fMask
& MIM_MENUDATA
)
892 lpmi
->dwMenuData
= Menu
->dwMenuData
;
893 if(lpmi
->fMask
& MIM_STYLE
)
894 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
896 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
898 lpmi
->cItems
= Menu
->cItems
;
900 lpmi
->iItem
= Menu
->iItem
;
901 lpmi
->cxMenu
= Menu
->cxMenu
;
902 lpmi
->cyMenu
= Menu
->cyMenu
;
903 lpmi
->spwndNotify
= Menu
->spwndNotify
;
904 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
905 lpmi
->iTop
= Menu
->iTop
;
906 lpmi
->iMaxTop
= Menu
->iMaxTop
;
907 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
909 lpmi
->fFlags
= Menu
->fFlags
;
910 lpmi
->Self
= Menu
->head
.h
;
911 lpmi
->TimeToHide
= Menu
->TimeToHide
;
912 lpmi
->Wnd
= Menu
->hWnd
;
918 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
920 if(lpmi
->fMask
& MIM_BACKGROUND
)
921 Menu
->hbrBack
= lpmi
->hbrBack
;
922 if(lpmi
->fMask
& MIM_HELPID
)
923 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
924 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
925 Menu
->cyMax
= lpmi
->cyMax
;
926 if(lpmi
->fMask
& MIM_MENUDATA
)
927 Menu
->dwMenuData
= lpmi
->dwMenuData
;
928 if(lpmi
->fMask
& MIM_STYLE
)
929 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
930 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
933 PITEM item
= Menu
->rgItems
;
934 for ( i
= Menu
->cItems
; i
; i
--, item
++)
936 if ( item
->spSubMenu
)
938 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
942 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
944 Menu
->iItem
= lpmi
->iItem
;
945 Menu
->cyMenu
= lpmi
->cyMenu
;
946 Menu
->cxMenu
= lpmi
->cxMenu
;
947 Menu
->spwndNotify
= lpmi
->spwndNotify
;
948 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
949 Menu
->iTop
= lpmi
->iTop
;
950 Menu
->iMaxTop
= lpmi
->iMaxTop
;
951 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
953 Menu
->TimeToHide
= lpmi
->TimeToHide
;
954 Menu
->hWnd
= lpmi
->Wnd
;
956 if ( lpmi
->fMask
& MIM_STYLE
)
958 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented wine\n");
959 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented wine\n");
960 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented wine\n");
966 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
967 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
971 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
973 lpmii
->fType
= MenuItem
->fType
;
975 if(lpmii
->fMask
& MIIM_BITMAP
)
977 lpmii
->hbmpItem
= MenuItem
->hbmp
;
979 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
981 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
982 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
984 if(lpmii
->fMask
& MIIM_DATA
)
986 lpmii
->dwItemData
= MenuItem
->dwItemData
;
988 if(lpmii
->fMask
& MIIM_ID
)
990 lpmii
->wID
= MenuItem
->wID
;
992 if(lpmii
->fMask
& MIIM_STATE
)
994 lpmii
->fState
= MenuItem
->fState
;
996 if(lpmii
->fMask
& MIIM_SUBMENU
)
998 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
1001 if ((lpmii
->fMask
& MIIM_STRING
) ||
1002 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1004 if (lpmii
->dwTypeData
== NULL
)
1006 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1009 { //// lpmii->lpstr can be read in user mode!!!!
1010 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
1011 min(lpmii
->cch
* sizeof(WCHAR
),
1012 MenuItem
->lpstr
.MaximumLength
));
1013 if (! NT_SUCCESS(Status
))
1015 SetLastNtError(Status
);
1021 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1023 lpmii
->Rect
.left
= MenuItem
->xItem
;
1024 lpmii
->Rect
.top
= MenuItem
->yItem
;
1025 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
1026 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
1027 lpmii
->dxTab
= MenuItem
->dxTab
;
1028 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
1029 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
1030 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
1037 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
1039 PMENU SubMenuObject
;
1040 BOOL circref
= FALSE
;
1042 if(!MenuItem
|| !MenuObject
|| !lpmii
)
1046 if ( lpmii
->fMask
& MIIM_FTYPE
)
1048 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
1049 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
1051 if (lpmii
->fMask
& MIIM_TYPE
)
1053 #if 0 //// Done in User32.
1054 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
1056 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1057 KeRosDumpStackFrames(NULL
, 20);
1058 /* This does not happen on Win9x/ME */
1059 SetLastNtError( ERROR_INVALID_PARAMETER
);
1064 * Delete the menu item type when changing type from
1067 if (MenuItem
->fType
!= lpmii
->fType
&&
1068 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
1070 FreeMenuText(MenuObject
,MenuItem
);
1071 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1072 MenuItem
->Xlpstr
= NULL
;
1074 if(lpmii
->fType
& MFT_BITMAP
)
1077 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1079 { /* Win 9x/Me stuff */
1080 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
1082 lpmii
->dwTypeData
= 0;
1085 if(lpmii
->fMask
& MIIM_BITMAP
)
1087 MenuItem
->hbmp
= lpmii
->hbmpItem
;
1088 if (MenuItem
->hbmp
<= HBMMENU_POPUP_MINIMIZE
&& MenuItem
->hbmp
>= HBMMENU_CALLBACK
)
1089 MenuItem
->fState
|= MFS_HBMMENUBMP
;
1091 MenuItem
->fState
&= ~MFS_HBMMENUBMP
;
1093 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
1095 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
1096 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
1098 if(lpmii
->fMask
& MIIM_DATA
)
1100 MenuItem
->dwItemData
= lpmii
->dwItemData
;
1102 if(lpmii
->fMask
& MIIM_ID
)
1104 MenuItem
->wID
= lpmii
->wID
;
1106 if(lpmii
->fMask
& MIIM_STATE
)
1108 /* Remove MFS_DEFAULT flag from all other menu items if this item
1109 has the MFS_DEFAULT state */
1110 if(lpmii
->fState
& MFS_DEFAULT
)
1111 UserSetMenuDefaultItem(MenuObject
, -1, 0);
1112 /* Update the menu item state flags */
1113 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
1116 if(lpmii
->fMask
& MIIM_SUBMENU
)
1118 if (lpmii
->hSubMenu
)
1120 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
1121 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
1123 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1125 if (MenuObject
== SubMenuObject
)
1128 ERR("Pop Up Menu Double Trouble!\n");
1129 SubMenuObject
= IntCreateMenu(&hMenu
,
1131 MenuObject
->head
.rpdesk
,
1132 (PPROCESSINFO
)MenuObject
->head
.hTaskWow
); // It will be marked.
1133 if (!SubMenuObject
) return FALSE
;
1134 IntReleaseMenuObject(SubMenuObject
); // This will be referenced again after insertion.
1137 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
1139 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1140 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
);
1143 /* Make sure the submenu is marked as a popup menu */
1144 SubMenuObject
->fFlags
|= MNF_POPUP
;
1145 // Now fix the test_subpopup_locked_by_menu tests....
1146 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1147 MenuItem
->spSubMenu
= SubMenuObject
;
1148 UserReferenceObject(SubMenuObject
);
1152 EngSetLastError( ERROR_INVALID_PARAMETER
);
1157 { // If submenu just dereference it.
1158 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
1159 MenuItem
->spSubMenu
= NULL
;
1163 if ((lpmii
->fMask
& MIIM_STRING
) ||
1164 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
1166 /* free the string when used */
1167 FreeMenuText(MenuObject
,MenuItem
);
1168 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
1169 MenuItem
->Xlpstr
= NULL
;
1171 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
1173 UNICODE_STRING Source
;
1175 if (!NT_VERIFY(lpmii
->cch
<= UNICODE_STRING_MAX_CHARS
))
1180 Source
.Length
= Source
.MaximumLength
= (USHORT
)(lpmii
->cch
* sizeof(WCHAR
));
1181 Source
.Buffer
= lpmii
->dwTypeData
;
1183 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
1184 if(MenuItem
->lpstr
.Buffer
!= NULL
)
1186 MenuItem
->lpstr
.Length
= 0;
1187 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
1188 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
1189 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
1191 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
1192 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
1197 if( !(MenuObject
->fFlags
& MNF_SYSMENU
) &&
1198 !MenuItem
->Xlpstr
&&
1199 !lpmii
->dwTypeData
&&
1200 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
1202 MenuItem
->fType
|= MFT_SEPARATOR
;
1204 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
1206 MenuItem
->xItem
= lpmii
->Rect
.left
;
1207 MenuItem
->yItem
= lpmii
->Rect
.top
;
1208 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
1209 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
1210 MenuItem
->dxTab
= lpmii
->dxTab
;
1211 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
1212 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
1213 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
1221 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
1226 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
1228 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
1230 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
1232 /* If the close item in the system menu change update the close button */
1235 switch (MenuItem
->wID
) // More than just close.
1243 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
1245 //RECTL rc = MenuObject->spwndNotify->rcWindow;
1247 /* Refresh the frame to reflect the change */
1248 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1250 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1253 UserPaintCaption(MenuObject
->spwndNotify
, DC_BUTTONS
);
1263 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
1268 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
1270 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
1272 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
1278 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1281 PITEM MenuItem
= MenuObject
->rgItems
;
1283 if (!MenuItem
) return FALSE
;
1285 /* reset all default-item flags */
1286 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1288 MenuItem
->fState
&= ~MFS_DEFAULT
;
1291 /* no default item */
1292 if(uItem
== (UINT
)-1)
1296 MenuItem
= MenuObject
->rgItems
;
1299 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1300 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1305 for (i
= 0; i
< MenuObject
->cItems
; i
++, MenuItem
++)
1307 if (MenuItem
->wID
== uItem
)
1309 MenuItem
->fState
|= MFS_DEFAULT
;
1319 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1322 PITEM MenuItem
= MenuObject
->rgItems
;
1325 if (!MenuItem
) return -1;
1327 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1330 if (i
>= MenuObject
->cItems
) return -1;
1333 /* default: don't return disabled items */
1334 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1336 /* search rekursiv when needed */
1337 if ( (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1341 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1343 if ( -1 != ret
) return ret
;
1345 /* when item not found in submenu, return the popup item */
1347 return ( fByPos
) ? i
: MenuItem
->wID
;
1357 if (!(pItem
= MENU_FindItem( &pMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1358 return pItem
->spSubMenu
;
1361 /***********************************************************************
1362 * MenuInitSysMenuPopup
1364 * Grey the appropriate items in System menu.
1366 void FASTCALL
MENU_InitSysMenuPopup(PMENU menu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
1371 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1372 IntEnableMenuItem( menu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1373 gray
= ((style
& WS_MAXIMIZE
) != 0);
1374 IntEnableMenuItem( menu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1375 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
1376 IntEnableMenuItem( menu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1377 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
1378 IntEnableMenuItem( menu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1379 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1380 IntEnableMenuItem( menu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
1381 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
1383 /* The menu item must keep its state if it's disabled */
1385 IntEnableMenuItem( menu
, SC_CLOSE
, MF_GRAYED
);
1387 /* Set default menu item */
1388 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
1389 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
1390 else DefItem
= SC_CLOSE
;
1392 UserSetMenuDefaultItem(menu
, DefItem
, MF_BYCOMMAND
);
1396 /***********************************************************************
1397 * MenuDrawPopupGlyph
1399 * Draws popup magic glyphs (can be found in system menu).
1401 static void FASTCALL
1402 MENU_DrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
1405 HFONT hFont
, hOldFont
;
1411 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1414 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1417 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1420 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1424 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
1427 RtlZeroMemory(&lf
, sizeof(LOGFONTW
));
1428 RECTL_vInflateRect(r
, -2, -2);
1429 lf
.lfHeight
= r
->bottom
- r
->top
;
1431 lf
.lfWeight
= FW_NORMAL
;
1432 lf
.lfCharSet
= DEFAULT_CHARSET
;
1433 RtlCopyMemory(lf
.lfFaceName
, L
"Marlett", sizeof(L
"Marlett"));
1434 hFont
= GreCreateFontIndirectW(&lf
);
1435 /* save font and text color */
1436 hOldFont
= NtGdiSelectFont(dc
, hFont
);
1437 clrsave
= GreGetTextColor(dc
);
1438 bkmode
= GreGetBkMode(dc
);
1439 /* set color and drawing mode */
1440 IntGdiSetBkMode(dc
, TRANSPARENT
);
1446 IntGdiSetTextColor(dc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
1447 GreTextOutW(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
1450 IntGdiSetTextColor(dc
, IntGetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
1451 /* draw selected symbol */
1452 GreTextOutW(dc
, r
->left
, r
->top
, &symbol
, 1);
1453 /* restore previous settings */
1454 IntGdiSetTextColor(dc
, clrsave
);
1455 NtGdiSelectFont(dc
, hOldFont
);
1456 IntGdiSetBkMode(dc
, bkmode
);
1457 GreDeleteObject(hFont
);
1460 /***********************************************************************
1461 * MENU_AdjustMenuItemRect
1463 * Adjust menu item rectangle according to scrolling state.
1466 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1468 if (menu
->dwArrowsOn
)
1470 UINT arrow_bitmap_height
;
1471 arrow_bitmap_height
= gpsi
->oembmi
[OBI_UPARROW
].cy
; ///// Menu up arrow! OBM_UPARROW
1472 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1473 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1477 /***********************************************************************
1478 * MENU_FindItemByCoords
1480 * Find the item at the specified coordinates (screen coords). Does
1481 * not work for child windows and therefore should not be called for
1482 * an arbitrary system menu.
1484 static ITEM
*MENU_FindItemByCoords( MENU
*menu
, POINT pt
, UINT
*pos
)
1489 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
1491 if (!IntGetWindowRect(pWnd
, &rect
)) return NULL
;
1492 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
)
1493 pt
.x
= rect
.right
- 1 - pt
.x
;
1497 item
= menu
->rgItems
;
1498 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1500 //rect = item->rect;
1501 rect
.left
= item
->xItem
;
1502 rect
.top
= item
->yItem
;
1503 rect
.right
= item
->cxItem
; // Do this for now......
1504 rect
.bottom
= item
->cyItem
;
1506 MENU_AdjustMenuItemRect(menu
, &rect
);
1507 if (RECTL_bPointInRect(&rect
, pt
.x
, pt
.y
))
1516 INT FASTCALL
IntMenuItemFromPoint(PWND pWnd
, HMENU hMenu
, POINT ptScreen
)
1518 MENU
*menu
= UserGetMenuObject(hMenu
);
1521 /*FIXME: Do we have to handle hWnd here? */
1522 if (!menu
) return -1;
1523 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
1527 /***********************************************************************
1530 * Find the menu item selected by a key press.
1531 * Return item id, -1 if none, -2 if we should close the menu.
1533 static UINT FASTCALL
MENU_FindItemByKey(PWND WndOwner
, PMENU menu
,
1534 WCHAR Key
, BOOL ForceMenuChar
)
1539 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, menu
);
1541 if (!menu
|| !VerifyMenu(menu
))
1542 menu
= co_IntGetSubMenu( UserGetMenuObject(WndOwner
->SystemMenu
), 0 );
1545 ITEM
*item
= menu
->rgItems
;
1547 if ( !ForceMenuChar
)
1550 BOOL cjk
= UserGetSystemMetrics( SM_DBCSENABLED
);
1552 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1554 LPWSTR text
= item
->Xlpstr
;
1557 const WCHAR
*p
= text
- 2;
1560 const WCHAR
*q
= p
+ 2;
1561 p
= wcschr (q
, '&');
1562 if (!p
&& cjk
) p
= wcschr (q
, '\036'); /* Japanese Win16 */
1564 while (p
!= NULL
&& p
[1] == '&');
1565 if (p
&& (towupper(p
[1]) == towupper(Key
))) return i
;
1570 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1571 Flags
|= menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0;
1573 MenuChar
= co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MENUCHAR
,
1574 MAKEWPARAM(Key
, Flags
), (LPARAM
) UserHMGetHandle(menu
));
1575 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1576 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1581 /***********************************************************************
1582 * MenuGetBitmapItemSize
1584 * Get the size of a bitmap item.
1586 static void FASTCALL
MENU_GetBitmapItemSize(PITEM lpitem
, SIZE
*size
, PWND WndOwner
)
1589 HBITMAP bmp
= lpitem
->hbmp
;
1591 size
->cx
= size
->cy
= 0;
1593 /* check if there is a magic menu item associated with this item */
1594 if (IS_MAGIC_BITMAP(bmp
))
1596 switch((INT_PTR
) bmp
)
1598 case (INT_PTR
)HBMMENU_CALLBACK
:
1600 MEASUREITEMSTRUCT measItem
;
1601 measItem
.CtlType
= ODT_MENU
;
1603 measItem
.itemID
= lpitem
->wID
;
1604 measItem
.itemWidth
= lpitem
->cxItem
- lpitem
->xItem
; //lpitem->Rect.right - lpitem->Rect.left;
1605 measItem
.itemHeight
= lpitem
->cyItem
- lpitem
->yItem
; //lpitem->Rect.bottom - lpitem->Rect.top;
1606 measItem
.itemData
= lpitem
->dwItemData
;
1607 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
1608 size
->cx
= measItem
.itemWidth
;
1609 size
->cy
= measItem
.itemHeight
;
1610 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem
.itemHeight
,measItem
.itemWidth
);
1615 case (INT_PTR
) HBMMENU_SYSTEM
:
1616 if (lpitem
->dwItemData
)
1618 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1622 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1623 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1624 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1625 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1626 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1627 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1628 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1629 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1630 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1631 /* FIXME: Why we need to subtract these magic values? */
1632 /* to make them smaller than the menu bar? */
1633 size
->cx
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1634 size
->cy
= UserGetSystemMetrics(SM_CYSIZE
) - 4;
1639 if (GreGetObject(bmp
, sizeof(BITMAP
), &bm
))
1641 size
->cx
= bm
.bmWidth
;
1642 size
->cy
= bm
.bmHeight
;
1646 /***********************************************************************
1647 * MenuDrawBitmapItem
1649 * Draw a bitmap item.
1651 static void FASTCALL
MENU_DrawBitmapItem(HDC hdc
, PITEM lpitem
, const RECT
*rect
,
1652 PMENU Menu
, PWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1658 int w
= rect
->right
- rect
->left
;
1659 int h
= rect
->bottom
- rect
->top
;
1660 int bmp_xoffset
= 0;
1663 HBITMAP hbmToDraw
= lpitem
->hbmp
;
1666 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1668 /* Check if there is a magic menu item associated with this item */
1669 if (IS_MAGIC_BITMAP(hbmToDraw
))
1675 switch ((INT_PTR
)hbmToDraw
)
1677 case (INT_PTR
)HBMMENU_SYSTEM
:
1678 if (lpitem
->dwItemData
)
1680 if (ValidateHwndNoErr((HWND
)lpitem
->dwItemData
))
1682 ERR("Get Item Data from this Window!!!\n");
1685 ERR("Draw Bitmap\n");
1686 bmp
= (HBITMAP
)lpitem
->dwItemData
;
1687 if (!GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1691 PCURICON_OBJECT pIcon
= NULL
;
1692 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1694 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1695 /* only use right half of the bitmap */
1696 //bmp_xoffset = bm.bmWidth / 2;
1697 //bm.bmWidth -= bmp_xoffset;
1700 pIcon
= NC_IconForWindow(WndOwner
);
1701 // FIXME: NC_IconForWindow should reference it for us */
1702 if (pIcon
) UserReferenceObject(pIcon
);
1707 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1708 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1709 LONG x
= rect
->left
- cx
/2 + 1 + (rect
->bottom
- rect
->top
)/2; // this is really what Window does
1710 LONG y
= (rect
->top
+ rect
->bottom
)/2 - cy
/2; // center
1711 UserDrawIconEx(hdc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1712 UserDereferenceObject(pIcon
);
1717 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1718 flags
= DFCS_CAPTIONRESTORE
;
1720 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1722 flags
= DFCS_CAPTIONMIN
;
1724 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1726 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1728 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1729 flags
= DFCS_CAPTIONCLOSE
;
1731 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1732 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1734 case (INT_PTR
)HBMMENU_CALLBACK
:
1736 DRAWITEMSTRUCT drawItem
;
1738 drawItem
.CtlType
= ODT_MENU
;
1740 drawItem
.itemID
= lpitem
->wID
;
1741 drawItem
.itemAction
= odaction
;
1742 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1743 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1744 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1745 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1746 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1747 drawItem
.itemState
|= (!(Menu
->fFlags
& MNF_UNDERLINE
))?ODS_NOACCEL
:0;
1748 drawItem
.itemState
|= (Menu
->fFlags
& MNF_INACTIVE
)?ODS_INACTIVE
:0;
1749 drawItem
.hwndItem
= (HWND
)UserHMGetHandle(Menu
);
1751 drawItem
.rcItem
= *rect
;
1752 drawItem
.itemData
= lpitem
->dwItemData
;
1753 /* some applications make this assumption on the DC's origin */
1754 GreSetViewportOrgEx( hdc
, lpitem
->xItem
, lpitem
->yItem
, &origorg
);
1755 RECTL_vOffsetRect( &drawItem
.rcItem
, - lpitem
->xItem
, - lpitem
->yItem
);
1756 co_IntSendMessage( UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1757 GreSetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1762 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1763 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1764 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1765 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1766 MENU_DrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1769 RECTL_vInflateRect(&r
, -1, -1);
1770 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
1771 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1775 if (!bmp
|| !GreGetObject( bmp
, sizeof(bm
), &bm
)) return;
1778 hdcMem
= NtGdiCreateCompatibleDC( hdc
);
1779 NtGdiSelectBitmap( hdcMem
, bmp
);
1780 /* handle fontsize > bitmap_height */
1781 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1783 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1784 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmp
)
1785 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
1788 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
1793 NtGdiBitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
, 0, 0);
1794 IntGdiDeleteDC( hdcMem
, FALSE
);
1798 IntGetDialogBaseUnits(VOID
)
1807 if ((hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
)))
1809 size
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&size
.cy
);
1810 if (size
.cx
) units
= MAKELONG( size
.cx
, size
.cy
);
1811 UserReleaseDC( 0, hdc
, FALSE
);
1818 /***********************************************************************
1821 * Calculate the size of the menu item and store it in lpitem->rect.
1823 static void FASTCALL
MENU_CalcItemSize( HDC hdc
, PITEM lpitem
, PMENU Menu
, PWND pwndOwner
,
1824 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1827 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
1828 UINT arrow_bitmap_width
;
1832 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, pwndOwner
, orgX
, orgY
);
1834 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
1836 MenuCharSize
.cx
= IntGetCharDimensions( hdc
, NULL
, (PDWORD
)&MenuCharSize
.cy
);
1838 RECTL_vSetRect( &Rect
, orgX
, orgY
, orgX
, orgY
);
1840 if (lpitem
->fType
& MF_OWNERDRAW
)
1842 MEASUREITEMSTRUCT mis
;
1843 mis
.CtlType
= ODT_MENU
;
1845 mis
.itemID
= lpitem
->wID
;
1846 mis
.itemData
= lpitem
->dwItemData
;
1847 mis
.itemHeight
= HIWORD( IntGetDialogBaseUnits());
1849 co_IntSendMessage( UserHMGetHandle(pwndOwner
), WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1850 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1851 * width of a menufont character to the width of an owner-drawn menu.
1853 Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1855 /* under at least win95 you seem to be given a standard
1856 height for the menu and the height value is ignored */
1857 Rect
.bottom
+= UserGetSystemMetrics(SM_CYMENUSIZE
);
1859 Rect
.bottom
+= mis
.itemHeight
;
1861 //lpitem->cxBmp = mis.itemWidth;
1862 //lpitem->cyBmp = mis.itemHeight;
1863 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis
.itemHeight
,mis
.itemWidth
);
1864 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1865 lpitem
->wID
, Rect
.right
-Rect
.left
,
1866 Rect
.bottom
-Rect
.top
, MenuCharSize
.cx
, MenuCharSize
.cy
);
1868 lpitem
->xItem
= Rect
.left
;
1869 lpitem
->yItem
= Rect
.top
;
1870 lpitem
->cxItem
= Rect
.right
;
1871 lpitem
->cyItem
= Rect
.bottom
;
1876 lpitem
->xItem
= orgX
;
1877 lpitem
->yItem
= orgY
;
1878 lpitem
->cxItem
= orgX
;
1879 lpitem
->cyItem
= orgY
;
1881 if (lpitem
->fType
& MF_SEPARATOR
)
1883 lpitem
->cyItem
+= UserGetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1885 lpitem
->cxItem
+= arrow_bitmap_width
+ MenuCharSize
.cx
;
1896 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1897 /* Keep the size of the bitmap in callback mode to be able
1898 * to draw it correctly */
1899 lpitem
->cxBmp
= size
.cx
;
1900 lpitem
->cyBmp
= size
.cy
;
1901 Menu
->cxTextAlign
= max(Menu
->cxTextAlign
, size
.cx
);
1902 lpitem
->cxItem
+= size
.cx
+ 2;
1903 itemheight
= size
.cy
+ 2;
1905 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1906 lpitem
->cxItem
+= 2 * check_bitmap_width
;
1907 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1908 lpitem
->dxTab
= lpitem
->cxItem
;
1909 lpitem
->cxItem
+= arrow_bitmap_width
;
1910 } else /* hbmpItem & MenuBar */ {
1911 MENU_GetBitmapItemSize(lpitem
, &size
, pwndOwner
);
1912 lpitem
->cxItem
+= size
.cx
;
1913 if( lpitem
->Xlpstr
) lpitem
->cxItem
+= 2;
1914 itemheight
= size
.cy
;
1916 /* Special case: Minimize button doesn't have a space behind it. */
1917 if (lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1918 lpitem
->hbmp
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1919 lpitem
->cxItem
-= 1;
1922 else if (!menuBar
) {
1923 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
1924 lpitem
->cxItem
+= check_bitmap_width
;
1925 lpitem
->cxItem
+= 4 + MenuCharSize
.cx
;
1926 lpitem
->dxTab
= lpitem
->cxItem
;
1927 lpitem
->cxItem
+= arrow_bitmap_width
;
1930 /* it must be a text item - unless it's the system menu */
1931 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->Xlpstr
) {
1932 HFONT hfontOld
= NULL
;
1933 RECT rc
;// = lpitem->Rect;
1934 LONG txtheight
, txtwidth
;
1936 rc
.left
= lpitem
->xItem
;
1937 rc
.top
= lpitem
->yItem
;
1938 rc
.right
= lpitem
->cxItem
; // Do this for now......
1939 rc
.bottom
= lpitem
->cyItem
;
1941 if ( lpitem
->fState
& MFS_DEFAULT
) {
1942 hfontOld
= NtGdiSelectFont( hdc
, ghMenuFontBold
);
1945 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
, DT_SINGLELINE
|DT_CALCRECT
);
1947 lpitem
->cxItem
+= rc
.right
- rc
.left
;
1948 itemheight
= max( max( itemheight
, txtheight
), UserGetSystemMetrics( SM_CYMENU
) - 1);
1950 lpitem
->cxItem
+= 2 * MenuCharSize
.cx
;
1952 if ((p
= wcschr( lpitem
->Xlpstr
, '\t' )) != NULL
) {
1955 int n
= (int)( p
- lpitem
->Xlpstr
);
1956 /* Item contains a tab (only meaningful in popup menus) */
1957 /* get text size before the tab */
1958 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, n
, &rc
,
1959 DT_SINGLELINE
|DT_CALCRECT
);
1960 txtwidth
= rc
.right
- rc
.left
;
1961 p
+= 1; /* advance past the Tab */
1962 /* get text size after the tab */
1963 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1964 DT_SINGLELINE
|DT_CALCRECT
);
1965 lpitem
->dxTab
+= txtwidth
;
1966 txtheight
= max( txtheight
, tmpheight
);
1967 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1968 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1970 txtheight
= DrawTextW( hdc
, lpitem
->Xlpstr
, -1, &rc
,
1971 DT_SINGLELINE
|DT_CALCRECT
);
1972 txtwidth
= rc
.right
- rc
.left
;
1973 lpitem
->dxTab
+= txtwidth
;
1975 lpitem
->cxItem
+= 2 + txtwidth
;
1976 itemheight
= max( itemheight
,
1977 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1981 NtGdiSelectFont (hdc
, hfontOld
);
1983 } else if( menuBar
) {
1984 itemheight
= max( itemheight
, UserGetSystemMetrics(SM_CYMENU
)-1);
1986 lpitem
->cyItem
+= itemheight
;
1987 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->xItem
, lpitem
->yItem
, lpitem
->cxItem
, lpitem
->cyItem
);
1990 /***********************************************************************
1991 * MENU_GetMaxPopupHeight
1994 MENU_GetMaxPopupHeight(PMENU lppop
)
1998 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1999 return lppop
->cyMax
;
2001 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
2002 return UserGetSystemMetrics(SM_CYSCREEN
) - UserGetSystemMetrics(SM_CYBORDER
);
2005 /***********************************************************************
2006 * MenuPopupMenuCalcSize
2008 * Calculate the size of a popup menu.
2010 static void FASTCALL
MENU_PopupMenuCalcSize(PMENU Menu
, PWND WndOwner
)
2015 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
2016 BOOL textandbmp
= FALSE
;
2018 Menu
->cxMenu
= Menu
->cyMenu
= 0;
2019 if (Menu
->cItems
== 0) return;
2021 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
2023 NtGdiSelectFont( hdc
, ghMenuFont
);
2028 Menu
->cxTextAlign
= 0;
2030 while (start
< Menu
->cItems
)
2032 lpitem
= &Menu
->rgItems
[start
];
2034 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2035 orgX
+= MENU_COL_SPACE
;
2036 orgY
= MENU_TOP_MARGIN
;
2038 maxTab
= maxTabWidth
= 0;
2039 /* Parse items until column break or end of menu */
2040 for (i
= start
; i
< Menu
->cItems
; i
++, lpitem
++)
2043 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2045 MENU_CalcItemSize(hdc
, lpitem
, Menu
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
2046 maxX
= max(maxX
, lpitem
->cxItem
);
2047 orgY
= lpitem
->cyItem
;
2048 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2050 maxTab
= max( maxTab
, lpitem
->dxTab
);
2051 maxTabWidth
= max(maxTabWidth
, lpitem
->cxItem
- lpitem
->dxTab
);
2053 if( lpitem
->Xlpstr
&& lpitem
->hbmp
) textandbmp
= TRUE
;
2056 /* Finish the column (set all items to the largest width found) */
2057 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
2058 for (lpitem
= &Menu
->rgItems
[start
]; start
< i
; start
++, lpitem
++)
2060 lpitem
->cxItem
= maxX
;
2061 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->dxTab
)
2062 lpitem
->dxTab
= maxTab
;
2064 Menu
->cyMenu
= max(Menu
->cyMenu
, orgY
);
2067 Menu
->cxMenu
= maxX
;
2068 /* if none of the items have both text and bitmap then
2069 * the text and bitmaps are all aligned on the left. If there is at
2070 * least one item with both text and bitmap then bitmaps are
2071 * on the left and texts left aligned with the right hand side
2073 if( !textandbmp
) Menu
->cxTextAlign
= 0;
2075 /* space for 3d border */
2076 Menu
->cyMenu
+= MENU_BOTTOM_MARGIN
;
2079 /* Adjust popup height if it exceeds maximum */
2080 maxHeight
= MENU_GetMaxPopupHeight(Menu
);
2081 Menu
->iMaxTop
= Menu
->cyMenu
- MENU_TOP_MARGIN
;
2082 if (Menu
->cyMenu
>= maxHeight
)
2084 Menu
->cyMenu
= maxHeight
;
2085 Menu
->dwArrowsOn
= 1;
2089 Menu
->dwArrowsOn
= 0;
2091 UserReleaseDC( 0, hdc
, FALSE
);
2094 /***********************************************************************
2095 * MENU_MenuBarCalcSize
2097 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2098 * height is off by 1 pixel which causes lengthy window relocations when
2099 * active document window is maximized/restored.
2101 * Calculate the size of the menu bar.
2103 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, PMENU lppop
, PWND pwndOwner
)
2106 UINT start
, i
, helpPos
;
2107 int orgX
, orgY
, maxY
;
2109 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
2110 if (lppop
->cItems
== 0) return;
2111 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2112 lppop
->cxMenu
= lprect
->right
- lprect
->left
;
2117 lppop
->cxTextAlign
= 0;
2118 while (start
< lppop
->cItems
)
2120 lpitem
= &lppop
->rgItems
[start
];
2121 orgX
= lprect
->left
;
2124 /* Parse items until line break or end of menu */
2125 for (i
= start
; i
< lppop
->cItems
; i
++, lpitem
++)
2127 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
2129 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
2131 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
2132 //debug_print_menuitem (" item: ", lpitem, "");
2133 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2134 MENU_CalcItemSize(hdc
, lpitem
, lppop
, pwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
2136 if (lpitem
->cxItem
> lprect
->right
)
2138 if (i
!= start
) break;
2139 else lpitem
->cxItem
= lprect
->right
;
2141 maxY
= max( maxY
, lpitem
->cyItem
);
2142 orgX
= lpitem
->cxItem
;
2145 /* Finish the line (set all items to the largest height found) */
2147 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2148 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2150 while (start
< i
) lppop
->rgItems
[start
++].cyItem
= maxY
;
2152 start
= i
; /* This works! */
2155 lprect
->bottom
= maxY
+ 1;
2156 lppop
->cyMenu
= lprect
->bottom
- lprect
->top
;
2158 /* Flush right all items between the MF_RIGHTJUSTIFY and */
2159 /* the last item (if several lines, only move the last line) */
2160 if (helpPos
== ~0U) return;
2161 lpitem
= &lppop
->rgItems
[lppop
->cItems
-1];
2162 orgY
= lpitem
->yItem
;
2163 orgX
= lprect
->right
;
2164 for (i
= lppop
->cItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
2165 if (lpitem
->yItem
!= orgY
) break; /* Other line */
2166 if (lpitem
->cxItem
>= orgX
) break; /* Too far right already */
2167 lpitem
->xItem
+= orgX
- lpitem
->cxItem
;
2168 lpitem
->cxItem
= orgX
;
2169 orgX
= lpitem
->xItem
;
2173 /***********************************************************************
2174 * MENU_DrawScrollArrows
2176 * Draw scroll arrows.
2178 static void MENU_DrawScrollArrows(PMENU lppop
, HDC hdc
)
2180 UINT arrow_bitmap_width
, arrow_bitmap_height
;
2184 arrow_bitmap_width
= gpsi
->oembmi
[OBI_DNARROW
].cx
;
2185 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2189 rect
.right
= lppop
->cxMenu
;
2190 rect
.bottom
= arrow_bitmap_height
;
2191 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2192 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2194 dfcrc
.right
= arrow_bitmap_width
;
2195 dfcrc
.bottom
= arrow_bitmap_height
;
2196 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, (lppop
->iTop
? 0 : DFCS_INACTIVE
)|DFCS_MENUARROWUP
);
2198 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2199 rect
.bottom
= lppop
->cyMenu
;
2200 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2201 if (!(lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
)))
2202 Flags
= DFCS_INACTIVE
;
2203 dfcrc
.left
= (lppop
->cxMenu
- arrow_bitmap_width
) / 2;
2204 dfcrc
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
2205 dfcrc
.right
= arrow_bitmap_width
;
2206 dfcrc
.bottom
= lppop
->cyMenu
;
2207 DrawFrameControl(hdc
, &dfcrc
, DFC_MENU
, Flags
|DFCS_MENUARROWDOWN
);
2210 /***********************************************************************
2213 * Draw a single menu item.
2215 static void FASTCALL
MENU_DrawMenuItem(PWND Wnd
, PMENU Menu
, PWND WndOwner
, HDC hdc
,
2216 PITEM lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
2220 BOOL flat_menu
= FALSE
;
2222 UINT arrow_bitmap_width
= 0;
2226 arrow_bitmap_width
= gpsi
->oembmi
[OBI_MNARROW
].cx
;
2229 if (lpitem
->fType
& MF_SYSMENU
)
2231 if (!(Wnd
->style
& WS_MINIMIZE
))
2233 NC_GetInsideRect(Wnd
, &rect
);
2234 UserDrawSysMenuButton(Wnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
2239 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2240 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
2244 if (lpitem
->fState
& MF_HILITE
)
2246 if(menuBar
&& !flat_menu
) {
2247 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_MENUTEXT
));
2248 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_MENU
));
2250 if (lpitem
->fState
& MF_GRAYED
)
2251 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_GRAYTEXT
));
2253 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHTTEXT
));
2254 IntGdiSetBkColor(hdc
, IntGetSysColor(COLOR_HIGHLIGHT
));
2259 if (lpitem
->fState
& MF_GRAYED
)
2260 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_GRAYTEXT
) );
2262 IntGdiSetTextColor( hdc
, IntGetSysColor( COLOR_MENUTEXT
) );
2263 IntGdiSetBkColor( hdc
, IntGetSysColor( bkgnd
) );
2266 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2267 //rect = lpitem->Rect;
2268 rect
.left
= lpitem
->xItem
;
2269 rect
.top
= lpitem
->yItem
;
2270 rect
.right
= lpitem
->cxItem
; // Do this for now......
2271 rect
.bottom
= lpitem
->cyItem
;
2273 MENU_AdjustMenuItemRect(Menu
, &rect
);
2275 if (lpitem
->fType
& MF_OWNERDRAW
)
2278 ** Experimentation under Windows reveals that an owner-drawn
2279 ** menu is given the rectangle which includes the space it requested
2280 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2281 ** and a popup-menu arrow. This is the value of lpitem->rect.
2282 ** Windows will leave all drawing to the application except for
2283 ** the popup-menu arrow. Windows always draws that itself, after
2284 ** the menu owner has finished drawing.
2287 COLORREF old_bk
, old_text
;
2289 dis
.CtlType
= ODT_MENU
;
2291 dis
.itemID
= lpitem
->wID
;
2292 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
2294 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
2295 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
2296 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
2297 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
2298 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
2299 if (!(Menu
->fFlags
& MNF_UNDERLINE
)) dis
.itemState
|= ODS_NOACCEL
;
2300 if (Menu
->fFlags
& MNF_INACTIVE
) dis
.itemState
|= ODS_INACTIVE
;
2301 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2302 dis
.hwndItem
= (HWND
) UserHMGetHandle(Menu
);
2305 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2306 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd
,
2307 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
2308 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
2310 TRACE("Ownerdraw: Width %d Height %d\n", dis
.rcItem
.right
-dis
.rcItem
.left
, dis
.rcItem
.bottom
-dis
.rcItem
.top
);
2311 old_bk
= GreGetBkColor(hdc
);
2312 old_text
= GreGetTextColor(hdc
);
2313 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_DRAWITEM
, 0, (LPARAM
) &dis
);
2314 IntGdiSetBkColor(hdc
, old_bk
);
2315 IntGdiSetTextColor(hdc
, old_text
);
2316 /* Draw the popup-menu arrow */
2317 if (!menuBar
&& lpitem
->spSubMenu
)
2320 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2321 rectTemp
.left
= rectTemp
.right
- UserGetSystemMetrics(SM_CXMENUCHECK
);
2322 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2327 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
2329 if (lpitem
->fState
& MF_HILITE
)
2333 RECTL_vInflateRect (&rect
, -1, -1);
2334 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENUHILIGHT
));
2335 RECTL_vInflateRect (&rect
, 1, 1);
2336 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2342 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_MENU
));
2343 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
2347 FillRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_HIGHLIGHT
));
2352 FillRect( hdc
, &rect
, IntGetSysColorBrush(bkgnd
) );
2354 IntGdiSetBkMode( hdc
, TRANSPARENT
);
2356 /* vertical separator */
2357 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
2362 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2364 rc
.bottom
= Height
- 3;
2367 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2368 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2369 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2370 NtGdiLineTo( hdc
, rc
.left
, rc
.bottom
);
2371 NtGdiSelectPen( hdc
, oldPen
);
2374 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
2377 /* horizontal separator */
2378 if (lpitem
->fType
& MF_SEPARATOR
)
2385 rc
.top
= (rc
.top
+ rc
.bottom
) / 2 - 1;
2388 oldPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject(DC_PEN
) );
2389 IntSetDCPenColor( hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2390 GreMoveTo( hdc
, rc
.left
, rc
.top
, NULL
);
2391 NtGdiLineTo( hdc
, rc
.right
, rc
.top
);
2392 NtGdiSelectPen( hdc
, oldPen
);
2395 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
2399 /* helper lines for debugging */
2400 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2401 FrameRect(hdc
, &rect
, NtGdiGetStockObject(BLACK_BRUSH
));
2402 NtGdiSelectPen(hdc
, NtGdiGetStockObject(DC_PEN
));
2403 IntSetDCPenColor(hdc
, IntGetSysColor(COLOR_WINDOWFRAME
));
2404 GreMoveTo(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
2405 NtGdiLineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
2407 #if 0 // breaks mdi menu bar icons.
2409 /* calculate the bitmap rectangle in coordinates relative
2410 * to the item rectangle */
2412 if( lpitem
->hbmp
== HBMMENU_CALLBACK
)
2415 bmprc
.left
= lpitem
->Xlpstr
? MenuCharSize
.cx
: 0;
2417 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)
2419 else if ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)
2422 bmprc
.left
= 4 + UserGetSystemMetrics(SM_CXMENUCHECK
);
2424 bmprc
.right
= bmprc
.left
+ lpitem
->cxBmp
;
2426 if( menuBar
&& !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2429 bmprc
.top
= (rect
.bottom
- rect
.top
- lpitem
->cyBmp
) / 2;
2431 bmprc
.bottom
= bmprc
.top
+ lpitem
->cyBmp
;
2437 INT y
= rect
.top
+ rect
.bottom
;
2439 BOOL checked
= FALSE
;
2440 UINT check_bitmap_width
= UserGetSystemMetrics( SM_CXMENUCHECK
);
2441 UINT check_bitmap_height
= UserGetSystemMetrics( SM_CYMENUCHECK
);
2442 /* Draw the check mark
2445 * Custom checkmark bitmaps are monochrome but not always 1bpp.
2447 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
)) {
2448 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
2449 lpitem
->hbmpUnchecked
;
2450 if (bm
) /* we have a custom bitmap */
2452 HDC hdcMem
= NtGdiCreateCompatibleDC( hdc
);
2454 NtGdiSelectBitmap( hdcMem
, bm
);
2455 NtGdiBitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
2456 check_bitmap_width
, check_bitmap_height
,
2457 hdcMem
, 0, 0, SRCCOPY
, 0,0);
2458 IntGdiDeleteDC( hdcMem
, FALSE
);
2461 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
2465 r
.right
= r
.left
+ check_bitmap_width
;
2466 DrawFrameControl( hdc
, &r
, DFC_MENU
,
2467 (lpitem
->fType
& MFT_RADIOCHECK
) ?
2468 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2472 if ( lpitem
->hbmp
)//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2474 RECT bmpRect
= rect
;
2475 if (!((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
) && !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2476 bmpRect
.left
+= check_bitmap_width
+ 2;
2477 if (!(checked
&& ((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
)))
2479 bmpRect
.right
= bmpRect
.left
+ lpitem
->cxBmp
;
2480 MENU_DrawBitmapItem(hdc
, lpitem
, &bmpRect
, Menu
, WndOwner
, odaction
, menuBar
);
2483 /* Draw the popup-menu arrow */
2484 if (lpitem
->spSubMenu
)
2487 RtlCopyMemory(&rectTemp
, &rect
, sizeof(RECT
));
2488 rectTemp
.left
= rectTemp
.right
- check_bitmap_width
;
2489 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
2492 if( !((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_NOCHECK
))
2493 rect
.left
+= check_bitmap_width
;
2494 rect
.right
-= arrow_bitmap_width
;
2496 else if( lpitem
->hbmp
)
2497 { /* Draw the bitmap */
2498 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
/*bmprc*/, Menu
, WndOwner
, odaction
, menuBar
);
2501 /* process text if present */
2507 UINT uFormat
= menuBar
?
2508 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
2509 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2511 if (((Menu
->fFlags
& MNS_STYLE_MASK
) & MNS_CHECKORBMP
))
2512 rect
.left
+= max(0, (int)(Menu
->cxTextAlign
- UserGetSystemMetrics(SM_CXMENUCHECK
)));
2514 rect
.left
+= Menu
->cxTextAlign
;
2516 if ( lpitem
->fState
& MFS_DEFAULT
)
2518 hfontOld
= NtGdiSelectFont(hdc
, ghMenuFontBold
);
2523 rect
.left
+= lpitem
->cxBmp
;
2524 if( !(lpitem
->hbmp
== HBMMENU_CALLBACK
))
2525 rect
.left
+= MenuCharSize
.cx
;
2526 rect
.right
-= MenuCharSize
.cx
;
2529 Text
= lpitem
->Xlpstr
;
2532 for (i
= 0; Text
[i
]; i
++)
2533 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
2539 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
2541 RECTL_vOffsetRect(&rect
, +1, +1);
2547 if(lpitem
->fState
& MF_GRAYED
)
2549 if (!(lpitem
->fState
& MF_HILITE
) )
2551 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2552 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2553 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2554 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2556 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2558 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
2560 /* paint the shortcut text */
2561 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
2563 if (L
'\t' == Text
[i
])
2565 rect
.left
= lpitem
->dxTab
;
2566 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
2570 rect
.right
= lpitem
->dxTab
;
2571 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2574 if (lpitem
->fState
& MF_GRAYED
)
2576 if (!(lpitem
->fState
& MF_HILITE
) )
2578 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2579 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNHIGHLIGHT
));
2580 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2581 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2583 IntGdiSetTextColor(hdc
, IntGetSysColor(COLOR_BTNSHADOW
));
2585 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2593 (lpitem
->fState
& (MF_HILITE
| MF_GRAYED
)) == MF_HILITE
)
2595 RECTL_vOffsetRect(&rect
, -1, -1);
2600 NtGdiSelectFont (hdc
, hfontOld
);
2605 /***********************************************************************
2608 * Paint a popup menu.
2610 static void FASTCALL
MENU_DrawPopupMenu(PWND wnd
, HDC hdc
, PMENU menu
)
2612 HBRUSH hPrevBrush
= 0, brush
= IntGetSysColorBrush(COLOR_MENU
);
2615 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd
, hdc
, menu
);
2617 IntGetClientRect( wnd
, &rect
);
2619 if (menu
&& menu
->hbrBack
) brush
= menu
->hbrBack
;
2620 if((hPrevBrush
= NtGdiSelectBrush( hdc
, brush
))
2621 && (NtGdiSelectFont( hdc
, ghMenuFont
)))
2625 NtGdiRectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2627 hPrevPen
= NtGdiSelectPen( hdc
, NtGdiGetStockObject( NULL_PEN
) );
2630 BOOL flat_menu
= FALSE
;
2632 UserSystemParametersInfo (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2634 FrameRect(hdc
, &rect
, IntGetSysColorBrush(COLOR_BTNSHADOW
));
2636 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2638 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu
), (menu
->fFlags
& MNS_STYLE_MASK
));
2639 /* draw menu items */
2640 if (menu
&& menu
->cItems
)
2645 item
= menu
->rgItems
;
2646 for( u
= menu
->cItems
; u
> 0; u
--, item
++)
2648 MENU_DrawMenuItem(wnd
, menu
, menu
->spwndNotify
, hdc
, item
,
2649 menu
->cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2651 /* draw scroll arrows */
2652 if (menu
->dwArrowsOn
)
2654 MENU_DrawScrollArrows(menu
, hdc
);
2660 NtGdiSelectBrush( hdc
, hPrevBrush
);
2665 /**********************************************************************
2668 PWND
MENU_IsMenuActive(VOID
)
2670 return ValidateHwndNoErr(top_popup
);
2673 /**********************************************************************
2676 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2678 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2680 void MENU_EndMenu( PWND pwnd
)
2683 menu
= UserGetMenuObject(top_popup_hmenu
);
2684 if ( menu
&& ( UserHMGetHandle(pwnd
) == menu
->hWnd
|| pwnd
== menu
->spwndNotify
) )
2686 if (fInsideMenuLoop
&& top_popup
)
2688 fInsideMenuLoop
= FALSE
;
2692 ERR("Already in End loop\n");
2697 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
2703 IntDrawMenuBarTemp(PWND pWnd
, HDC hDC
, LPRECT Rect
, PMENU pMenu
, HFONT Font
)
2706 HFONT FontOld
= NULL
;
2707 BOOL flat_menu
= FALSE
;
2709 UserSystemParametersInfo(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2713 pMenu
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2721 if (Rect
== NULL
|| !pMenu
)
2723 return UserGetSystemMetrics(SM_CYMENU
);
2726 TRACE("(%x, %x, %p, %x, %x)\n", pWnd
, hDC
, Rect
, pMenu
, Font
);
2728 FontOld
= NtGdiSelectFont(hDC
, Font
);
2730 if (pMenu
->cyMenu
== 0)
2732 MENU_MenuBarCalcSize(hDC
, Rect
, pMenu
, pWnd
);
2735 Rect
->bottom
= Rect
->top
+ pMenu
->cyMenu
;
2737 FillRect(hDC
, Rect
, IntGetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2739 NtGdiSelectPen(hDC
, NtGdiGetStockObject(DC_PEN
));
2740 IntSetDCPenColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
2741 GreMoveTo(hDC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2742 NtGdiLineTo(hDC
, Rect
->right
, Rect
->bottom
- 1);
2744 if (pMenu
->cItems
== 0)
2746 NtGdiSelectFont(hDC
, FontOld
);
2747 return UserGetSystemMetrics(SM_CYMENU
);
2750 for (i
= 0; i
< pMenu
->cItems
; i
++)
2752 MENU_DrawMenuItem(pWnd
, pMenu
, pWnd
, hDC
, &pMenu
->rgItems
[i
], pMenu
->cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2755 NtGdiSelectFont(hDC
, FontOld
);
2757 return pMenu
->cyMenu
;
2760 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, PWND pWnd
, BOOL suppress_draw
)
2763 PMENU lppop
= UserGetMenuObject(UlongToHandle(pWnd
->IDMenu
));
2767 // No menu. Do not reserve any space
2773 return UserGetSystemMetrics(SM_CYMENU
);
2778 hfontOld
= NtGdiSelectFont(hDC
, ghMenuFont
);
2780 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, pWnd
);
2782 lprect
->bottom
= lprect
->top
+ lppop
->cyMenu
;
2784 if (hfontOld
) NtGdiSelectFont( hDC
, hfontOld
);
2786 return lppop
->cyMenu
;
2790 return IntDrawMenuBarTemp(pWnd
, hDC
, lprect
, lppop
, NULL
);
2794 /***********************************************************************
2797 * Popup menu initialization before WM_ENTERMENULOOP.
2799 static BOOL
MENU_InitPopup( PWND pWndOwner
, PMENU menu
, UINT flags
)
2802 PPOPUPMENU pPopupMenu
;
2804 LARGE_STRING WindowName
;
2805 UNICODE_STRING ClassName
;
2806 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2808 TRACE("owner=%p hmenu=%p\n", pWndOwner
, menu
);
2810 menu
->spwndNotify
= pWndOwner
;
2812 if (flags
& TPM_LAYOUTRTL
|| pWndOwner
->ExStyle
& WS_EX_LAYOUTRTL
)
2813 ex_style
= WS_EX_LAYOUTRTL
;
2815 ClassName
.Buffer
= WC_MENU
;
2816 ClassName
.Length
= 0;
2818 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
2819 RtlZeroMemory(&Cs
, sizeof(Cs
));
2820 Cs
.style
= WS_POPUP
;
2821 Cs
.dwExStyle
= ex_style
;
2822 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
2823 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
2824 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
2825 Cs
.lpCreateParams
= UserHMGetHandle(menu
);
2826 Cs
.hwndParent
= UserHMGetHandle(pWndOwner
);
2828 /* NOTE: In Windows, top menu popup is not owned. */
2829 pWndCreated
= co_UserCreateWindowEx( &Cs
, &ClassName
, &WindowName
, NULL
);
2831 if( !pWndCreated
) return FALSE
;
2834 // Setup pop up menu structure.
2836 menu
->hWnd
= UserHMGetHandle(pWndCreated
);
2838 pPopupMenu
= ((PMENUWND
)pWndCreated
)->ppopupmenu
;
2840 pPopupMenu
->spwndActivePopup
= pWndCreated
; // top_popup = MenuInfo.Wnd or menu->hWnd
2841 pPopupMenu
->spwndNotify
= pWndOwner
; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2842 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2844 pPopupMenu
->fIsTrackPopup
= !!(flags
& TPM_POPUPMENU
);
2845 pPopupMenu
->fIsSysMenu
= !!(flags
& TPM_SYSTEM_MENU
);
2846 pPopupMenu
->fNoNotify
= !!(flags
& TPM_NONOTIFY
);
2847 pPopupMenu
->fRightButton
= !!(flags
& TPM_RIGHTBUTTON
);
2848 pPopupMenu
->fSynchronous
= !!(flags
& TPM_RETURNCMD
);
2850 if (pPopupMenu
->fRightButton
)
2851 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_RBUTTON
) & 0x8000);
2853 pPopupMenu
->fFirstClick
= !!(UserGetKeyState(VK_LBUTTON
) & 0x8000);
2855 if (gpsi
->aiSysMet
[SM_MENUDROPALIGNMENT
] ||
2856 menu
->fFlags
& MNF_RTOL
)
2858 pPopupMenu
->fDroppedLeft
= TRUE
;
2863 /***********************************************************************
2866 * Display a popup menu.
2868 static BOOL FASTCALL
MENU_ShowPopup(PWND pwndOwner
, PMENU menu
, UINT id
, UINT flags
,
2875 USER_REFERENCE_ENTRY Ref
;
2876 BOOL bIsPopup
= (flags
& TPM_POPUPMENU
) != 0;
2878 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x\n",
2879 pwndOwner
, menu
, id
, x
, y
);
2881 if (menu
->iItem
!= NO_SELECTED_ITEM
)
2883 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2884 menu
->iItem
= NO_SELECTED_ITEM
;
2887 menu
->dwArrowsOn
= 0;
2888 MENU_PopupMenuCalcSize(menu
, pwndOwner
);
2890 /* adjust popup menu pos so that it fits within the desktop */
2892 width
= menu
->cxMenu
+ UserGetSystemMetrics(SM_CXBORDER
);
2893 height
= menu
->cyMenu
+ UserGetSystemMetrics(SM_CYBORDER
);
2895 /* FIXME: should use item rect */
2898 monitor
= UserMonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2900 if (flags
& TPM_LAYOUTRTL
)
2901 flags
^= TPM_RIGHTALIGN
;
2903 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2904 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2906 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2907 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2909 if( x
+ width
> monitor
->rcMonitor
.right
)
2911 if( x
+ width
> monitor
->rcMonitor
.right
)
2913 /* If we would flip around our origin, would we go off screen on the other side?
2914 Or is our origin itself too far to the right already? */
2915 if (!bIsPopup
|| x
- width
< monitor
->rcMonitor
.left
|| x
> monitor
->rcMonitor
.right
)
2916 x
= monitor
->rcMonitor
.right
- width
;
2921 if( x
< monitor
->rcMonitor
.left
)
2923 /* If we would flip around our origin, would we go off screen on the other side? */
2924 if (!bIsPopup
|| x
+ width
> monitor
->rcMonitor
.right
)
2925 x
= monitor
->rcMonitor
.left
;
2930 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2932 if( y
+ height
> monitor
->rcMonitor
.bottom
)
2934 /* If we would flip around our origin, would we go off screen on the other side?
2935 Or is our origin itself too far to the bottom already? */
2936 if (!bIsPopup
|| y
- height
< monitor
->rcMonitor
.top
|| y
> monitor
->rcMonitor
.bottom
)
2937 y
= monitor
->rcMonitor
.bottom
- height
;
2942 if( y
< monitor
->rcMonitor
.top
)
2944 /* If we would flip around our origin, would we go off screen on the other side? */
2945 if (!bIsPopup
|| y
+ height
> monitor
->rcMonitor
.bottom
)
2946 y
= monitor
->rcMonitor
.top
;
2951 pWnd
= ValidateHwndNoErr( menu
->hWnd
);
2955 ERR("menu->hWnd bad hwnd %p\n",menu
->hWnd
);
2960 top_popup
= menu
->hWnd
;
2961 top_popup_hmenu
= UserHMGetHandle(menu
);
2964 /* Display the window */
2965 UserRefObjectCo(pWnd
, &Ref
);
2966 co_WinPosSetWindowPos( pWnd
, HWND_TOPMOST
, x
, y
, width
, height
, SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2968 co_IntUpdateWindows(pWnd
, RDW_ALLCHILDREN
, FALSE
);
2970 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2971 UserDerefObjectCo(pWnd
);
2976 /***********************************************************************
2977 * MENU_EnsureMenuItemVisible
2979 void MENU_EnsureMenuItemVisible(PMENU lppop
, UINT wIndex
, HDC hdc
)
2981 USER_REFERENCE_ENTRY Ref
;
2982 if (lppop
->dwArrowsOn
)
2984 ITEM
*item
= &lppop
->rgItems
[wIndex
];
2985 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2986 UINT nOldPos
= lppop
->iTop
;
2988 UINT arrow_bitmap_height
;
2989 PWND pWnd
= ValidateHwndNoErr(lppop
->hWnd
);
2991 IntGetClientRect(pWnd
, &rc
);
2993 arrow_bitmap_height
= gpsi
->oembmi
[OBI_DNARROW
].cy
;
2995 rc
.top
+= arrow_bitmap_height
;
2996 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2998 nMaxHeight
-= UserGetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2999 UserRefObjectCo(pWnd
, &Ref
);
3000 if (item
->cyItem
> lppop
->iTop
+ nMaxHeight
)
3002 lppop
->iTop
= item
->cyItem
- nMaxHeight
;
3003 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
3004 MENU_DrawScrollArrows(lppop
, hdc
);
3005 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3007 else if (item
->yItem
- MENU_TOP_MARGIN
< lppop
->iTop
)
3009 lppop
->iTop
= item
->yItem
- MENU_TOP_MARGIN
;
3010 IntScrollWindow(pWnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
3011 MENU_DrawScrollArrows(lppop
, hdc
);
3012 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3014 UserDerefObjectCo(pWnd
);
3018 /***********************************************************************
3021 static void FASTCALL
MENU_SelectItem(PWND pwndOwner
, PMENU menu
, UINT wIndex
,
3022 BOOL sendMenuSelect
, PMENU topmenu
)
3027 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner
, menu
, wIndex
, sendMenuSelect
);
3029 if (!menu
|| !menu
->cItems
) return;
3031 pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3035 if (menu
->iItem
== wIndex
) return;
3037 if (menu
->fFlags
& MNF_POPUP
)
3038 hdc
= UserGetDCEx(pWnd
, 0, DCX_USESTYLE
);
3040 hdc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3043 top_popup
= menu
->hWnd
; //pPopupMenu->spwndActivePopup or
3044 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
3045 top_popup_hmenu
= UserHMGetHandle(menu
); //pPopupMenu->spmenu
3048 NtGdiSelectFont( hdc
, ghMenuFont
);
3050 /* Clear previous highlighted item */
3051 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3053 menu
->rgItems
[menu
->iItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
3054 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
, &menu
->rgItems
[menu
->iItem
],
3055 menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
),
3059 /* Highlight new item (if any) */
3060 menu
->iItem
= wIndex
;
3061 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3063 if (!(menu
->rgItems
[wIndex
].fType
& MF_SEPARATOR
))
3065 menu
->rgItems
[wIndex
].fState
|= MF_HILITE
;
3066 MENU_EnsureMenuItemVisible(menu
, wIndex
, hdc
);
3067 MENU_DrawMenuItem(pWnd
, menu
, pwndOwner
, hdc
,
3068 &menu
->rgItems
[wIndex
], menu
->cyMenu
, !(menu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
3072 ITEM
*ip
= &menu
->rgItems
[menu
->iItem
];
3073 WPARAM wParam
= MAKEWPARAM( ip
->spSubMenu
? wIndex
: ip
->wID
,
3074 ip
->fType
| ip
->fState
|
3075 (ip
->spSubMenu
? MF_POPUP
: 0) |
3076 (menu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3078 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(menu
));
3081 else if (sendMenuSelect
)
3086 pos
= MENU_FindSubMenu(&topmenu
, menu
);
3087 if (pos
!= NO_SELECTED_ITEM
)
3089 ITEM
*ip
= &topmenu
->rgItems
[pos
];
3090 WPARAM wParam
= MAKEWPARAM( Pos
, ip
->fType
| ip
->fState
|
3091 (ip
->spSubMenu
? MF_POPUP
: 0) |
3092 (topmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
3094 co_IntSendMessage(UserHMGetHandle(pwndOwner
), WM_MENUSELECT
, wParam
, (LPARAM
) UserHMGetHandle(topmenu
));
3098 UserReleaseDC(pWnd
, hdc
, FALSE
);
3101 /***********************************************************************
3104 * Moves currently selected item according to the Offset parameter.
3105 * If there is no selection then it should select the last item if
3106 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3108 static void FASTCALL
MENU_MoveSelection(PWND pwndOwner
, PMENU menu
, INT offset
)
3112 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner
, menu
, offset
);
3114 if ((!menu
) || (!menu
->rgItems
)) return;
3116 if ( menu
->iItem
!= NO_SELECTED_ITEM
)
3118 if ( menu
->cItems
== 1 )
3121 for (i
= menu
->iItem
+ offset
; i
>= 0 && i
< menu
->cItems
3123 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3125 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3130 for ( i
= (offset
> 0) ? 0 : menu
->cItems
- 1;
3131 i
>= 0 && i
< menu
->cItems
; i
+= offset
)
3132 if (!(menu
->rgItems
[i
].fType
& MF_SEPARATOR
))
3134 MENU_SelectItem( pwndOwner
, menu
, i
, TRUE
, 0 );
3139 /***********************************************************************
3142 * Hide the sub-popup menus of this menu.
3144 static void FASTCALL
MENU_HideSubPopups(PWND pWndOwner
, PMENU Menu
,
3145 BOOL SendMenuSelect
, UINT wFlags
)
3147 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner
, Menu
, SendMenuSelect
);
3149 if ( Menu
&& top_popup
)
3153 if (Menu
->iItem
!= NO_SELECTED_ITEM
)
3155 Item
= &Menu
->rgItems
[Menu
->iItem
];
3156 if (!(Item
->spSubMenu
) ||
3157 !(Item
->fState
& MF_MOUSESELECT
)) return;
3158 Item
->fState
&= ~MF_MOUSESELECT
;
3163 if (Item
->spSubMenu
)
3166 if (!VerifyMenu(Item
->spSubMenu
)) return;
3167 pWnd
= ValidateHwndNoErr(Item
->spSubMenu
->hWnd
);
3168 MENU_HideSubPopups(pWndOwner
, Item
->spSubMenu
, FALSE
, wFlags
);
3169 MENU_SelectItem(pWndOwner
, Item
->spSubMenu
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3170 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu
,pWndOwner
->IDMenu
);
3171 co_UserDestroyWindow(pWnd
);
3173 /* Native returns handle to destroyed window */
3174 if (!(wFlags
& TPM_NONOTIFY
))
3176 co_IntSendMessage( UserHMGetHandle(pWndOwner
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(Item
->spSubMenu
),
3177 MAKELPARAM(0, IS_SYSTEM_MENU(Item
->spSubMenu
)) );
3180 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3181 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3183 Item
->spSubMenu
->hWnd
= NULL
;
3189 /***********************************************************************
3192 * Display the sub-menu of the selected item of this menu.
3193 * Return the handle of the submenu, or menu if no submenu to display.
3195 static PMENU FASTCALL
MENU_ShowSubPopup(PWND WndOwner
, PMENU Menu
, BOOL SelectFirst
, UINT Flags
)
3202 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, Menu
, SelectFirst
);
3204 if (!Menu
) return Menu
;
3206 if (Menu
->iItem
== NO_SELECTED_ITEM
) return Menu
;
3208 Item
= &Menu
->rgItems
[Menu
->iItem
];
3209 if (!(Item
->spSubMenu
) || (Item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
3212 /* message must be sent before using item,
3213 because nearly everything may be changed by the application ! */
3215 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3216 if (!(Flags
& TPM_NONOTIFY
))
3218 co_IntSendMessage(UserHMGetHandle(WndOwner
), WM_INITMENUPOPUP
,
3219 (WPARAM
) UserHMGetHandle(Item
->spSubMenu
),
3220 MAKELPARAM(Menu
->iItem
, IS_SYSTEM_MENU(Menu
)));
3223 Item
= &Menu
->rgItems
[Menu
->iItem
];
3224 //Rect = ItemInfo.Rect;
3225 Rect
.left
= Item
->xItem
;
3226 Rect
.top
= Item
->yItem
;
3227 Rect
.right
= Item
->cxItem
; // Do this for now......
3228 Rect
.bottom
= Item
->cyItem
;
3230 pWnd
= ValidateHwndNoErr(Menu
->hWnd
);
3232 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3233 if (!(Item
->fState
& MF_HILITE
))
3235 if (Menu
->fFlags
& MNF_POPUP
) Dc
= UserGetDCEx(pWnd
, NULL
, DCX_USESTYLE
);
3236 else Dc
= UserGetDCEx(pWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3238 NtGdiSelectFont(Dc
, ghMenuFont
);
3240 Item
->fState
|= MF_HILITE
;
3241 MENU_DrawMenuItem(pWnd
, Menu
, WndOwner
, Dc
, Item
, Menu
->cyMenu
,
3242 !(Menu
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3244 UserReleaseDC(pWnd
, Dc
, FALSE
);
3247 if (!Item
->yItem
&& !Item
->xItem
&& !Item
->cyItem
&& !Item
->cxItem
)
3249 Item
->xItem
= Rect
.left
;
3250 Item
->yItem
= Rect
.top
;
3251 Item
->cxItem
= Rect
.right
; // Do this for now......
3252 Item
->cyItem
= Rect
.bottom
;
3254 Item
->fState
|= MF_MOUSESELECT
;
3256 if (IS_SYSTEM_MENU(Menu
))
3258 MENU_InitSysMenuPopup(Item
->spSubMenu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
3260 NC_GetSysPopupPos(pWnd
, &Rect
);
3261 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
3262 Rect
.top
= Rect
.bottom
;
3263 Rect
.right
= UserGetSystemMetrics(SM_CXSIZE
);
3264 Rect
.bottom
= UserGetSystemMetrics(SM_CYSIZE
);
3268 IntGetWindowRect(pWnd
, &Rect
);
3269 if (Menu
->fFlags
& MNF_POPUP
)
3272 rc
.left
= Item
->xItem
;
3273 rc
.top
= Item
->yItem
;
3274 rc
.right
= Item
->cxItem
; // Do this for now......
3275 rc
.bottom
= Item
->cyItem
;
3277 MENU_AdjustMenuItemRect(Menu
, &rc
);
3279 /* The first item in the popup menu has to be at the
3280 same y position as the focused menu item */
3281 if(Flags
& TPM_LAYOUTRTL
)
3282 Rect
.left
+= UserGetSystemMetrics(SM_CXBORDER
);
3284 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - UserGetSystemMetrics(SM_CXBORDER
);
3285 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3286 Rect
.right
= rc
.left
- rc
.right
+ UserGetSystemMetrics(SM_CXBORDER
);
3287 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3288 - UserGetSystemMetrics(SM_CYBORDER
);
3292 if(Flags
& TPM_LAYOUTRTL
)
3293 Rect
.left
+= Rect
.right
- Item
->xItem
; //ItemInfo.Rect.left;
3295 Rect
.left
+= Item
->xItem
; //ItemInfo.Rect.left;
3296 Rect
.top
+= Item
->cyItem
; //ItemInfo.Rect.bottom;
3297 Rect
.right
= Item
->cxItem
- Item
->xItem
; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3298 Rect
.bottom
= Item
->cyItem
- Item
->yItem
; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3302 /* use default alignment for submenus */
3303 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3305 MENU_InitPopup( WndOwner
, Item
->spSubMenu
, Flags
);
3307 MENU_ShowPopup( WndOwner
, Item
->spSubMenu
, Menu
->iItem
, Flags
,
3308 Rect
.left
, Rect
.top
);
3311 MENU_MoveSelection(WndOwner
, Item
->spSubMenu
, ITEM_NEXT
);
3313 return Item
->spSubMenu
;
3316 /***********************************************************************
3317 * MenuExecFocusedItem
3319 * Execute a menu item (for instance when user pressed Enter).
3320 * Return the wID of the executed item. Otherwise, -1 indicating
3321 * that no menu item was executed, -2 if a popup is shown;
3322 * Have to receive the flags for the TrackPopupMenu options to avoid
3323 * sending unwanted message.
3326 static INT FASTCALL
MENU_ExecFocusedItem(MTRACKER
*pmt
, PMENU Menu
, UINT Flags
)
3330 TRACE("%p menu=%p\n", pmt
, Menu
);
3332 if (!Menu
|| !Menu
->cItems
|| Menu
->iItem
== NO_SELECTED_ITEM
)
3337 Item
= &Menu
->rgItems
[Menu
->iItem
];
3339 TRACE("%p %08x %p\n", Menu
, Item
->wID
, Item
->spSubMenu
);
3341 if (!(Item
->spSubMenu
))
3343 if (!(Item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(Item
->fType
& MF_SEPARATOR
))
3345 /* If TPM_RETURNCMD is set you return the id, but
3346 do not send a message to the owner */
3347 if (!(Flags
& TPM_RETURNCMD
))
3349 if (Menu
->fFlags
& MNF_SYSMENU
)
3351 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_SYSCOMMAND
, Item
->wID
,
3352 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3356 DWORD dwStyle
= ((Menu
->fFlags
& MNS_STYLE_MASK
) | ( pmt
->TopMenu
? (pmt
->TopMenu
->fFlags
& MNS_STYLE_MASK
) : 0) );
3358 if (dwStyle
& MNS_NOTIFYBYPOS
)
3359 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_MENUCOMMAND
, Menu
->iItem
, (LPARAM
)UserHMGetHandle(Menu
));
3361 UserPostMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_COMMAND
, Item
->wID
, 0);
3369 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, Menu
, TRUE
, Flags
);
3376 /***********************************************************************
3377 * MenuSwitchTracking
3379 * Helper function for menu navigation routines.
3381 static void FASTCALL
MENU_SwitchTracking(MTRACKER
* pmt
, PMENU PtMenu
, UINT Index
, UINT wFlags
)
3383 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenu
, Index
);
3385 if ( pmt
->TopMenu
!= PtMenu
&&
3386 !((PtMenu
->fFlags
| pmt
->TopMenu
->fFlags
) & MNF_POPUP
) )
3388 /* both are top level menus (system and menu-bar) */
3389 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3390 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3391 pmt
->TopMenu
= PtMenu
;
3395 MENU_HideSubPopups(pmt
->OwnerWnd
, PtMenu
, FALSE
, wFlags
);
3398 MENU_SelectItem(pmt
->OwnerWnd
, PtMenu
, Index
, TRUE
, NULL
);
3401 /***********************************************************************
3404 * Return TRUE if we can go on with menu tracking.
3406 static BOOL FASTCALL
MENU_ButtonDown(MTRACKER
* pmt
, PMENU PtMenu
, UINT Flags
)
3408 TRACE("%x PtMenu=%p\n", pmt
, PtMenu
);
3414 if (IS_SYSTEM_MENU(PtMenu
))
3416 item
= PtMenu
->rgItems
;
3420 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &id
);
3425 if (PtMenu
->iItem
!= id
)
3426 MENU_SwitchTracking(pmt
, PtMenu
, id
, Flags
);
3428 /* If the popup menu is not already "popped" */
3429 if (!(item
->fState
& MF_MOUSESELECT
))
3431 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3436 /* Else the click was on the menu bar, finish the tracking */
3441 /***********************************************************************
3444 * Return the value of MenuExecFocusedItem if
3445 * the selected item was not a popup. Else open the popup.
3446 * A -1 return value indicates that we go on with menu tracking.
3449 static INT FASTCALL
MENU_ButtonUp(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3451 TRACE("%p pmenu=%x\n", pmt
, PtMenu
);
3458 if ( IS_SYSTEM_MENU(PtMenu
) )
3460 item
= PtMenu
->rgItems
;
3464 item
= MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Id
);
3467 if (item
&& ( PtMenu
->iItem
== Id
))
3469 if (!(item
->spSubMenu
))
3471 INT ExecutedMenuId
= MENU_ExecFocusedItem( pmt
, PtMenu
, Flags
);
3472 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3473 return ExecutedMenuId
;
3476 /* If we are dealing with the menu bar */
3477 /* and this is a click on an already "popped" item: */
3478 /* Stop the menu tracking and close the opened submenus */
3479 if (pmt
->TopMenu
== PtMenu
&& PtMenu
->TimeToHide
)
3484 if ( IntGetMenu(PtMenu
->hWnd
) == PtMenu
)
3486 PtMenu
->TimeToHide
= TRUE
;
3492 /***********************************************************************
3495 * Walks menu chain trying to find a menu pt maps to.
3497 static PMENU FASTCALL
MENU_PtMenu(PMENU menu
, POINT pt
)
3502 if (!menu
) return NULL
;
3504 /* try subpopup first (if any) */
3505 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3507 pItem
= menu
->rgItems
;
3508 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3509 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3511 ret
= MENU_PtMenu( pItem
->spSubMenu
, pt
);
3515 /* check the current window (avoiding WM_HITTEST) */
3518 PWND pWnd
= ValidateHwndNoErr(menu
->hWnd
);
3519 INT ht
= GetNCHitEx(pWnd
, pt
);
3520 if ( menu
->fFlags
& MNF_POPUP
)
3522 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= menu
;
3524 else if (ht
== HTSYSMENU
)
3525 ret
= get_win_sys_menu(menu
->hWnd
);
3526 else if (ht
== HTMENU
)
3527 ret
= IntGetMenu( menu
->hWnd
);
3532 /***********************************************************************
3535 * Return TRUE if we can go on with menu tracking.
3537 static BOOL FASTCALL
MENU_MouseMove(MTRACKER
*pmt
, PMENU PtMenu
, UINT Flags
)
3539 UINT Index
= NO_SELECTED_ITEM
;
3543 if (IS_SYSTEM_MENU(PtMenu
))
3546 //// ReactOS only HACK: CORE-2338
3547 // Windows tracks mouse moves to the system menu but does not open it.
3548 // Only keyboard tracking can do that.
3550 TRACE("SystemMenu\n");
3551 return TRUE
; // Stay inside the Loop!
3554 MENU_FindItemByCoords( PtMenu
, pmt
->Pt
, &Index
);
3557 if (Index
== NO_SELECTED_ITEM
)
3559 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NO_SELECTED_ITEM
, TRUE
, pmt
->TopMenu
);
3561 else if (PtMenu
->iItem
!= Index
)
3563 MENU_SwitchTracking(pmt
, PtMenu
, Index
, Flags
);
3564 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, PtMenu
, FALSE
, Flags
);
3569 /***********************************************************************
3572 * Return the handle of the selected sub-popup menu (if any).
3574 static PMENU
MENU_GetSubPopup( PMENU menu
)
3578 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3580 item
= &menu
->rgItems
[menu
->iItem
];
3581 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3583 return item
->spSubMenu
;
3588 /***********************************************************************
3591 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3593 static LRESULT FASTCALL
MENU_DoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3597 /* When skipping left, we need to do something special after the
3599 if (Vk
== VK_LEFT
&& pmt
->TopMenu
->iItem
== 0)
3603 /* When skipping right, for the non-system menu, we need to
3604 handle the last non-special menu item (ie skip any window
3605 icons such as MDI maximize, restore or close) */
3606 else if ((Vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(pmt
->TopMenu
))
3608 UINT i
= pmt
->TopMenu
->iItem
+ 1;
3609 while (i
< pmt
->TopMenu
->cItems
) {
3610 if ((pmt
->TopMenu
->rgItems
[i
].wID
>= SC_SIZE
&&
3611 pmt
->TopMenu
->rgItems
[i
].wID
<= SC_RESTORE
)) {
3615 if (i
== pmt
->TopMenu
->cItems
) {
3619 /* When skipping right, we need to cater for the system menu */
3620 else if ((Vk
== VK_RIGHT
) && IS_SYSTEM_MENU(pmt
->TopMenu
))
3622 if (pmt
->TopMenu
->iItem
== (pmt
->TopMenu
->cItems
- 1)) {
3629 MDINEXTMENU NextMenu
;
3636 MenuTmp
= (IS_SYSTEM_MENU(pmt
->TopMenu
)) ? co_IntGetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3637 NextMenu
.hmenuIn
= UserHMGetHandle(MenuTmp
);
3638 NextMenu
.hmenuNext
= NULL
;
3639 NextMenu
.hwndNext
= NULL
;
3640 co_IntSendMessage(UserHMGetHandle(pmt
->OwnerWnd
), WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3642 TRACE("%p [%p] -> %p [%p]\n",
3643 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3645 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3647 hNewWnd
= UserHMGetHandle(pmt
->OwnerWnd
);
3648 if (IS_SYSTEM_MENU(pmt
->TopMenu
))
3650 /* switch to the menu bar */
3652 if (pmt
->OwnerWnd
->style
& WS_CHILD
|| !(MenuTmp
= IntGetMenu(hNewWnd
))) return FALSE
;
3656 Id
= MenuTmp
->cItems
- 1;
3658 /* Skip backwards over any system predefined icons,
3659 eg. MDI close, restore etc icons */
3661 (MenuTmp
->rgItems
[Id
].wID
>= SC_SIZE
&&
3662 MenuTmp
->rgItems
[Id
].wID
<= SC_RESTORE
)) Id
--;
3665 hNewMenu
= UserHMGetHandle(MenuTmp
);
3667 else if (pmt
->OwnerWnd
->style
& WS_SYSMENU
)
3669 /* switch to the system menu */
3670 MenuTmp
= get_win_sys_menu(hNewWnd
);
3671 if (MenuTmp
) hNewMenu
= UserHMGetHandle(MenuTmp
);
3676 else /* application returned a new menu to switch to */
3678 hNewMenu
= NextMenu
.hmenuNext
;
3679 hNewWnd
= NextMenu
.hwndNext
;
3681 if ((MenuTmp
= UserGetMenuObject(hNewMenu
)) && (pwndTemp
= ValidateHwndNoErr(hNewWnd
)))
3683 if ( pwndTemp
->style
& WS_SYSMENU
&& (get_win_sys_menu(hNewWnd
) == MenuTmp
) )
3685 /* get the real system menu */
3686 MenuTmp
= get_win_sys_menu(hNewWnd
);
3687 hNewMenu
= UserHMGetHandle(MenuTmp
);
3689 else if (pwndTemp
->style
& WS_CHILD
|| IntGetMenu(hNewWnd
) != MenuTmp
)
3691 /* FIXME: Not sure what to do here;
3692 * perhaps try to track NewMenu as a popup? */
3694 WARN(" -- got confused.\n");
3701 if (hNewMenu
!= UserHMGetHandle(pmt
->TopMenu
))
3703 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3705 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3706 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, wFlags
);
3709 if (hNewWnd
!= UserHMGetHandle(pmt
->OwnerWnd
))
3711 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3712 pmt
->OwnerWnd
= ValidateHwndNoErr(hNewWnd
);
3713 ///// Use thread pms!!!!
3714 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, hNewWnd
);
3715 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3716 co_UserSetCapture(UserHMGetHandle(pmt
->OwnerWnd
));
3717 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
;
3720 pmt
->TopMenu
= pmt
->CurrentMenu
= UserGetMenuObject(hNewMenu
); /* all subpopups are hidden */
3721 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->TopMenu
, Id
, TRUE
, 0);
3728 /***********************************************************************
3731 * The idea is not to show the popup if the next input message is
3732 * going to hide it anyway.
3734 static BOOL FASTCALL
MENU_SuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3738 msg
.hwnd
= UserHMGetHandle(pmt
->OwnerWnd
); ////// ? silly wine'isms?
3740 co_IntGetPeekMessage( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3741 pmt
->TrackFlags
|= TF_SKIPREMOVE
;
3746 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3747 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3749 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
, FALSE
);
3750 co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
, FALSE
);
3751 if( msg
.message
== WM_KEYDOWN
&&
3752 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3754 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3760 /* failures go through this */
3761 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3765 /***********************************************************************
3768 * Handle a VK_ESCAPE key event in a menu.
3770 static BOOL FASTCALL
MENU_KeyEscape(MTRACKER
*pmt
, UINT Flags
)
3772 BOOL EndMenu
= TRUE
;
3774 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3776 if (pmt
->CurrentMenu
&& (pmt
->CurrentMenu
->fFlags
& MNF_POPUP
))
3778 PMENU MenuPrev
, MenuTmp
;
3780 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3782 /* close topmost popup */
3783 while (MenuTmp
!= pmt
->CurrentMenu
)
3786 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3789 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3790 pmt
->CurrentMenu
= MenuPrev
;
3798 /***********************************************************************
3801 * Handle a VK_LEFT key event in a menu.
3803 static void FASTCALL
MENU_KeyLeft(MTRACKER
* pmt
, UINT Flags
, UINT msg
)
3805 PMENU MenuTmp
, MenuPrev
;
3808 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3810 /* Try to move 1 column left (if possible) */
3811 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3813 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, PrevCol
, TRUE
, 0);
3817 /* close topmost popup */
3818 while (MenuTmp
!= pmt
->CurrentMenu
)
3821 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3824 MENU_HideSubPopups(pmt
->OwnerWnd
, MenuPrev
, TRUE
, Flags
);
3825 pmt
->CurrentMenu
= MenuPrev
;
3827 if ((MenuPrev
== pmt
->TopMenu
) && !(pmt
->TopMenu
->fFlags
& MNF_POPUP
))
3829 /* move menu bar selection if no more popups are left */
3831 if (!MENU_DoNextMenu(pmt
, VK_LEFT
, Flags
))
3832 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_PREV
);
3834 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3836 /* A sublevel menu was displayed - display the next one
3837 * unless there is another displacement coming up */
3839 if (!MENU_SuspendPopup(pmt
, msg
))
3840 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
,
3846 /***********************************************************************
3849 * Handle a VK_RIGHT key event in a menu.
3851 static void FASTCALL
MENU_KeyRight(MTRACKER
*pmt
, UINT Flags
, UINT msg
)
3856 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3857 pmt
->CurrentMenu
, pmt
->TopMenu
);
3859 if ((pmt
->TopMenu
->fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3861 /* If already displaying a popup, try to display sub-popup */
3863 menutmp
= pmt
->CurrentMenu
;
3864 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, menutmp
, TRUE
, Flags
);
3866 /* if subpopup was displayed then we are done */
3867 if (menutmp
!= pmt
->CurrentMenu
) return;
3870 /* Check to see if there's another column */
3871 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3873 TRACE("Going to %d.\n", NextCol
);
3874 MENU_SelectItem(pmt
->OwnerWnd
, pmt
->CurrentMenu
, NextCol
, TRUE
, 0);
3878 if (!(pmt
->TopMenu
->fFlags
& MNF_POPUP
)) /* menu bar tracking */
3880 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3882 MENU_HideSubPopups(pmt
->OwnerWnd
, pmt
->TopMenu
, FALSE
, Flags
);
3883 menutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3890 /* try to move to the next item */
3891 if ( !MENU_DoNextMenu(pmt
, VK_RIGHT
, Flags
))
3892 MENU_MoveSelection(pmt
->OwnerWnd
, pmt
->TopMenu
, ITEM_NEXT
);
3894 if ( menutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3896 if ( !MENU_SuspendPopup(pmt
, msg
) )
3897 pmt
->CurrentMenu
= MENU_ShowSubPopup(pmt
->OwnerWnd
, pmt
->TopMenu
, TRUE
, Flags
);
3902 /***********************************************************************
3905 * Menu tracking code.
3907 static INT FASTCALL
MENU_TrackMenu(PMENU pmenu
, UINT wFlags
, INT x
, INT y
,
3908 PWND pwnd
, const RECT
*lprect
)
3912 INT executedMenuId
= -1;
3916 BOOL enterIdleSent
= FALSE
;
3917 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
3919 if (pti
!= pwnd
->head
.pti
)
3921 ERR("Not the same PTI!!!!\n");
3925 mt
.CurrentMenu
= pmenu
;
3931 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3932 UserHMGetHandle(pmenu
), wFlags
, x
, y
, UserHMGetHandle(pwnd
), lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3933 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3935 pti
->MessageQueue
->QF_flags
&= ~QF_ACTIVATIONCHANGE
;
3937 if (wFlags
& TPM_BUTTONDOWN
)
3939 /* Get the result in order to start the tracking or not */
3940 fRemove
= MENU_ButtonDown( &mt
, pmenu
, wFlags
);
3941 fInsideMenuLoop
= fRemove
;
3944 if (wFlags
& TF_ENDMENU
) fInsideMenuLoop
= FALSE
;
3946 if (wFlags
& TPM_POPUPMENU
&& pmenu
->cItems
== 0) // Tracking empty popup menu...
3948 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
3949 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
3950 co_UserSetCapture(NULL
); /* release the capture */
3954 capture_win
= IntGetCapture();
3956 while (fInsideMenuLoop
)
3958 BOOL ErrorExit
= FALSE
;
3959 if (!VerifyMenu( mt
.CurrentMenu
)) /* sometimes happens if I do a window manager close */
3962 /* we have to keep the message in the queue until it's
3963 * clear that menu loop is not over yet. */
3967 if (co_IntGetPeekMessage( &msg
, 0, 0, 0, PM_NOREMOVE
, FALSE
))
3969 if (!IntCallMsgFilter( &msg
, MSGF_MENU
)) break;
3970 /* remove the message from the queue */
3971 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
3975 /* ReactOS Checks */
3976 if (!VerifyWnd(mt
.OwnerWnd
) ||
3977 !ValidateHwndNoErr(mt
.CurrentMenu
->hWnd
) ||
3978 pti
->MessageQueue
->QF_flags
& QF_ACTIVATIONCHANGE
||
3979 capture_win
!= IntGetCapture() ) // Should not happen, but this is ReactOS...
3981 ErrorExit
= TRUE
; // Do not wait on dead windows, now win test_capture_4 works.
3987 HWND win
= mt
.CurrentMenu
->fFlags
& MNF_POPUP
? mt
.CurrentMenu
->hWnd
: NULL
;
3988 enterIdleSent
= TRUE
;
3989 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3991 co_IntWaitMessage(NULL
, 0, 0);
3995 if (ErrorExit
) break; // Gracefully dropout.
3997 /* check if EndMenu() tried to cancel us, by posting this message */
3998 if (msg
.message
== WM_CANCELMODE
)
4000 /* we are now out of the loop */
4001 fInsideMenuLoop
= FALSE
;
4003 /* remove the message from the queue */
4004 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4006 /* break out of internal loop, ala ESCAPE */
4012 if ( (msg
.hwnd
== mt
.CurrentMenu
->hWnd
) || ((msg
.message
!=WM_TIMER
) && (msg
.message
!=WM_SYSTIMER
)) )
4013 enterIdleSent
=FALSE
;
4016 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
4019 * Use the mouse coordinates in lParam instead of those in the MSG
4020 * struct to properly handle synthetic messages. They are already
4021 * in screen coordinates.
4023 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
4024 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
4026 /* Find a menu for this mouse event */
4027 pmMouse
= MENU_PtMenu( mt
.TopMenu
, mt
.Pt
);
4031 /* no WM_NC... messages in captured state */
4033 case WM_RBUTTONDBLCLK
:
4034 case WM_RBUTTONDOWN
:
4035 if (!(wFlags
& TPM_RIGHTBUTTON
))
4037 if ( msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
4041 case WM_LBUTTONDBLCLK
:
4042 case WM_LBUTTONDOWN
:
4043 /* If the message belongs to the menu, removes it from the queue */
4044 /* Else, end menu tracking */
4045 fRemove
= MENU_ButtonDown(&mt
, pmMouse
, wFlags
);
4046 fInsideMenuLoop
= fRemove
;
4047 if ( msg
.message
== WM_LBUTTONDBLCLK
||
4048 msg
.message
== WM_RBUTTONDBLCLK
) fInsideMenuLoop
= FALSE
; // Must exit or loop forever!
4052 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
4055 /* Check if a menu was selected by the mouse */
4058 executedMenuId
= MENU_ButtonUp( &mt
, pmMouse
, wFlags
);
4060 /* End the loop if executedMenuId is an item ID */
4061 /* or if the job was done (executedMenuId = 0). */
4062 fRemove
= (executedMenuId
!= -1);
4063 fInsideMenuLoop
= !fRemove
;
4065 /* No menu was selected by the mouse */
4066 /* if the function was called by TrackPopupMenu, continue
4067 with the menu tracking. If not, stop it */
4069 fInsideMenuLoop
= ((wFlags
& TPM_POPUPMENU
) ? TRUE
: FALSE
);
4074 /* the selected menu item must be changed every time */
4075 /* the mouse moves. */
4078 fInsideMenuLoop
|= MENU_MouseMove( &mt
, pmMouse
, wFlags
);
4080 } /* switch(msg.message) - mouse */
4082 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4084 fRemove
= TRUE
; /* Keyboard messages are always removed */
4093 fInsideMenuLoop
= FALSE
;
4098 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4099 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4103 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4104 if (!(mt
.CurrentMenu
->fFlags
& MNF_POPUP
))
4105 mt
.CurrentMenu
= MENU_ShowSubPopup(mt
.OwnerWnd
, mt
.TopMenu
, TRUE
, wFlags
);
4106 else /* otherwise try to move selection */
4107 MENU_MoveSelection(mt
.OwnerWnd
, mt
.CurrentMenu
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4111 MENU_KeyLeft( &mt
, wFlags
, msg
.message
);
4115 MENU_KeyRight( &mt
, wFlags
, msg
.message
);
4119 fInsideMenuLoop
= !MENU_KeyEscape(&mt
, wFlags
);
4125 hi
.cbSize
= sizeof(HELPINFO
);
4126 hi
.iContextType
= HELPINFO_MENUITEM
;
4127 if (mt
.CurrentMenu
->iItem
== NO_SELECTED_ITEM
)
4130 hi
.iCtrlId
= pmenu
->rgItems
[mt
.CurrentMenu
->iItem
].wID
;
4131 hi
.hItemHandle
= UserHMGetHandle(mt
.CurrentMenu
);
4132 hi
.dwContextId
= pmenu
->dwContextHelpId
;
4133 hi
.MousePos
= msg
.pt
;
4134 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_HELP
, 0, (LPARAM
)&hi
);
4139 IntTranslateKbdMessage(&msg
, 0);
4142 break; /* WM_KEYDOWN */
4150 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4152 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4153 fEndMenu
= (executedMenuId
!= -2);
4154 fInsideMenuLoop
= !fEndMenu
;
4158 /* Hack to avoid control chars. */
4159 /* We will find a better way real soon... */
4160 if (msg
.wParam
< 32) break;
4162 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
4164 if (pos
== (UINT
)-2) fInsideMenuLoop
= FALSE
;
4165 else if (pos
== (UINT
)-1) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4168 MENU_SelectItem(mt
.OwnerWnd
, mt
.CurrentMenu
, pos
, TRUE
, 0);
4169 executedMenuId
= MENU_ExecFocusedItem(&mt
, mt
.CurrentMenu
, wFlags
);
4170 fEndMenu
= (executedMenuId
!= -2);
4171 fInsideMenuLoop
= !fEndMenu
;
4175 } /* switch(msg.message) - kbd */
4179 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4180 IntDispatchMessage( &msg
);
4184 if (fInsideMenuLoop
) fRemove
= TRUE
;
4186 /* finally remove message from the queue */
4188 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4189 co_IntGetPeekMessage( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
, FALSE
);
4190 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4193 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4194 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4195 co_UserSetCapture(NULL
); /* release the capture */
4197 /* If dropdown is still painted and the close box is clicked on
4198 then the menu will be destroyed as part of the DispatchMessage above.
4199 This will then invalidate the menu handle in mt.hTopMenu. We should
4200 check for this first. */
4201 if ( VerifyMenu( mt
.TopMenu
) )
4203 if (VerifyWnd(mt
.OwnerWnd
))
4205 MENU_HideSubPopups(mt
.OwnerWnd
, mt
.TopMenu
, FALSE
, wFlags
);
4207 if (mt
.TopMenu
->fFlags
& MNF_POPUP
)
4209 PWND pwndTM
= ValidateHwndNoErr(mt
.TopMenu
->hWnd
);
4212 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, pwndTM
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4214 co_UserDestroyWindow(pwndTM
);
4216 mt
.TopMenu
->hWnd
= NULL
;
4218 if (!(wFlags
& TPM_NONOTIFY
))
4220 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(mt
.TopMenu
),
4221 MAKELPARAM(0, IS_SYSTEM_MENU(mt
.TopMenu
)) );
4224 MENU_SelectItem( mt
.OwnerWnd
, mt
.TopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
4225 co_IntSendMessage( UserHMGetHandle(mt
.OwnerWnd
), WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4228 /* Reset the variable for hiding menu */
4229 mt
.TopMenu
->TimeToHide
= FALSE
;
4232 EngSetLastError( ERROR_SUCCESS
);
4233 /* The return value is only used by TrackPopupMenu */
4234 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4235 if (executedMenuId
== -1) executedMenuId
= 0;
4236 return executedMenuId
;
4239 /***********************************************************************
4242 static BOOL FASTCALL
MENU_InitTracking(PWND pWnd
, PMENU Menu
, BOOL bPopup
, UINT wFlags
)
4245 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4247 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd
), UserHMGetHandle(Menu
));
4249 co_UserHideCaret(0);
4251 /* This makes the menus of applications built with Delphi work.
4252 * It also enables menus to be displayed in more than one window,
4253 * but there are some bugs left that need to be fixed in this case.
4257 Menu
->hWnd
= UserHMGetHandle(pWnd
);
4261 top_popup
= Menu
->hWnd
;
4262 top_popup_hmenu
= UserHMGetHandle(Menu
);
4265 fInsideMenuLoop
= TRUE
;
4268 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4269 if (!(wFlags
& TPM_NONOTIFY
))
4271 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_ENTERMENULOOP
, bPopup
, 0 );
4275 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4277 capture_win
= (wFlags
& TPM_POPUPMENU
) ? Menu
->hWnd
: UserHMGetHandle(pWnd
);
4278 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, capture_win
); // 1
4279 co_UserSetCapture(capture_win
); // 2
4280 pti
->MessageQueue
->QF_flags
|= QF_CAPTURELOCKED
; // Set the Q bits so noone can change this!
4282 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_SETCURSOR
, (WPARAM
)UserHMGetHandle(pWnd
), HTCAPTION
);
4284 if (!(wFlags
& TPM_NONOTIFY
))
4286 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENU
, (WPARAM
)UserHMGetHandle(Menu
), 0 );
4287 /* If an app changed/recreated menu bar entries in WM_INITMENU
4288 * menu sizes will be recalculated once the menu created/shown.
4292 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4294 Menu
->fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4299 /***********************************************************************
4302 static BOOL FASTCALL
MENU_ExitTracking(PWND pWnd
, BOOL bPopup
, UINT wFlags
)
4304 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd
), bPopup
);
4306 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4308 if (!(wFlags
& TPM_NONOTIFY
))
4309 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_EXITMENULOOP
, bPopup
, 0 );
4311 co_UserShowCaret(0);
4314 top_popup_hmenu
= NULL
;
4319 /***********************************************************************
4320 * MenuTrackMouseMenuBar
4322 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4324 VOID
MENU_TrackMouseMenuBar( PWND pWnd
, ULONG ht
, POINT pt
)
4326 PMENU pMenu
= (ht
== HTSYSMENU
) ? IntGetSystemMenu(pWnd
, FALSE
) : IntGetMenu( UserHMGetHandle(pWnd
) ); // See 74276 and CORE-12801
4327 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4329 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd
, ht
, pt
.x
, pt
.y
);
4331 if (pWnd
->ExStyle
& WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4332 if (VerifyMenu(pMenu
))
4334 /* map point to parent client coordinates */
4335 PWND Parent
= UserGetAncestor(pWnd
, GA_PARENT
);
4336 if (Parent
!= UserGetDesktopWindow())
4338 IntScreenToClient(Parent
, &pt
);
4341 MENU_InitTracking(pWnd
, pMenu
, FALSE
, wFlags
);
4342 /* fetch the window menu again, it may have changed */
4343 pMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pWnd
) ) : IntGetMenu( UserHMGetHandle(pWnd
) );
4344 MENU_TrackMenu(pMenu
, wFlags
, pt
.x
, pt
.y
, pWnd
, NULL
);
4345 MENU_ExitTracking(pWnd
, FALSE
, wFlags
);
4349 /***********************************************************************
4350 * MenuTrackKbdMenuBar
4352 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4354 VOID
MENU_TrackKbdMenuBar(PWND pwnd
, UINT wParam
, WCHAR wChar
)
4356 UINT uItem
= NO_SELECTED_ITEM
;
4358 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4360 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd
), wParam
, wChar
);
4362 /* find window that has a menu */
4364 while (!( (pwnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) )
4365 if (!(pwnd
= UserGetAncestor( pwnd
, GA_PARENT
))) return;
4367 /* check if we have to track a system menu */
4369 TrackMenu
= IntGetMenu( UserHMGetHandle(pwnd
) );
4370 if (!TrackMenu
|| (pwnd
->style
& WS_MINIMIZE
) != 0 || wChar
== ' ' )
4372 if (!(pwnd
->style
& WS_SYSMENU
)) return;
4373 TrackMenu
= get_win_sys_menu( UserHMGetHandle(pwnd
) );
4375 wParam
|= HTSYSMENU
; /* prevent item lookup */
4378 if (!VerifyMenu( TrackMenu
)) return;
4380 MENU_InitTracking( pwnd
, TrackMenu
, FALSE
, wFlags
);
4382 /* fetch the window menu again, it may have changed */
4383 TrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( UserHMGetHandle(pwnd
) ) : IntGetMenu( UserHMGetHandle(pwnd
) );
4385 if( wChar
&& wChar
!= ' ' )
4387 uItem
= MENU_FindItemByKey( pwnd
, TrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4388 if ( uItem
>= (UINT
)(-2) )
4390 if( uItem
== (UINT
)(-1) ) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
4391 /* schedule end of menu tracking */
4392 wFlags
|= TF_ENDMENU
;
4397 MENU_SelectItem( pwnd
, TrackMenu
, uItem
, TRUE
, 0 );
4399 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4401 if( uItem
== NO_SELECTED_ITEM
)
4402 MENU_MoveSelection( pwnd
, TrackMenu
, ITEM_NEXT
);
4404 UserPostMessage( UserHMGetHandle(pwnd
), WM_KEYDOWN
, VK_RETURN
, 0 );
4408 MENU_TrackMenu( TrackMenu
, wFlags
, 0, 0, pwnd
, NULL
);
4409 MENU_ExitTracking( pwnd
, FALSE
, wFlags
);
4412 /**********************************************************************
4413 * TrackPopupMenuEx (USER32.@)
4415 BOOL WINAPI
IntTrackPopupMenuEx( PMENU menu
, UINT wFlags
, int x
, int y
,
4416 PWND pWnd
, LPTPMPARAMS lpTpm
)
4419 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
4421 if (pti
!= pWnd
->head
.pti
)
4423 ERR("Must be the same pti!\n");
4427 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4428 UserHMGetHandle(menu
), wFlags
, x
, y
, UserHMGetHandle(pWnd
), lpTpm
); //,
4429 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4431 if (menu
->hWnd
&& IntIsWindow(menu
->hWnd
))
4433 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4437 if (MENU_InitPopup( pWnd
, menu
, wFlags
))
4439 MENU_InitTracking(pWnd
, menu
, TRUE
, wFlags
);
4441 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4442 if (!(wFlags
& TPM_NONOTIFY
))
4444 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_INITMENUPOPUP
, (WPARAM
) UserHMGetHandle(menu
), 0);
4447 if (menu
->fFlags
& MNF_SYSMENU
)
4448 MENU_InitSysMenuPopup( menu
, pWnd
->style
, pWnd
->pcls
->style
, HTSYSMENU
);
4450 if (MENU_ShowPopup(pWnd
, menu
, 0, wFlags
| TPM_POPUPMENU
, x
, y
))
4451 ret
= MENU_TrackMenu( menu
, wFlags
| TPM_POPUPMENU
, 0, 0, pWnd
,
4452 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4455 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
4456 pti
->MessageQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
4457 co_UserSetCapture(NULL
); /* release the capture */
4460 MENU_ExitTracking(pWnd
, TRUE
, wFlags
);
4464 PWND pwndM
= ValidateHwndNoErr( menu
->hWnd
);
4465 if (pwndM
) // wine hack around this with their destroy function.
4467 if (!(pWnd
->state
& WNDS_DESTROYED
))
4468 co_UserDestroyWindow( pwndM
); // Fix wrong error return.
4472 if (!(wFlags
& TPM_NONOTIFY
))
4474 co_IntSendMessage( UserHMGetHandle(pWnd
), WM_UNINITMENUPOPUP
, (WPARAM
)UserHMGetHandle(menu
),
4475 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4493 PPOPUPMENU pPopupMenu
;
4497 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
4503 if (Message
!= WM_NCCREATE
)
4505 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4508 Wnd
->fnid
= FNID_MENU
;
4509 pPopupMenu
= DesktopHeapAlloc( Wnd
->head
.rpdesk
, sizeof(POPUPMENU
) );
4510 if (pPopupMenu
== NULL
)
4514 pPopupMenu
->posSelectedItem
= NO_SELECTED_ITEM
;
4515 pPopupMenu
->spwndPopupMenu
= Wnd
;
4516 ((PMENUWND
)Wnd
)->ppopupmenu
= pPopupMenu
;
4517 TRACE("Pop Up Menu is Setup! Msg %d\n",Message
);
4523 if (Wnd
->fnid
!= FNID_MENU
)
4525 ERR("Wrong window class for Menu! fnid %x\n",Wnd
->fnid
);
4528 pPopupMenu
= ((PMENUWND
)Wnd
)->ppopupmenu
;
4536 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
4537 pPopupMenu
->spmenu
= UserGetMenuObject(cs
->lpCreateParams
);
4538 if (pPopupMenu
->spmenu
)
4540 UserReferenceObject(pPopupMenu
->spmenu
);
4545 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
4546 *lResult
= MA_NOACTIVATE
;
4552 IntBeginPaint(Wnd
, &ps
);
4553 MENU_DrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
);
4554 IntEndPaint(Wnd
, &ps
);
4558 case WM_PRINTCLIENT
:
4560 MENU_DrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
);
4569 /* zero out global pointer in case resident popup window was destroyed. */
4572 if (UserHMGetHandle(Wnd
) == top_popup
)
4575 top_popup_hmenu
= NULL
;
4580 ERR("No Window Pop Up!\n");
4586 if (pPopupMenu
->spmenu
)
4588 IntReleaseMenuObject(pPopupMenu
->spmenu
);
4590 DesktopHeapFree(Wnd
->head
.rpdesk
, pPopupMenu
);
4591 ((PMENUWND
)Wnd
)->ppopupmenu
= 0;
4592 Wnd
->fnid
= FNID_DESTROY
;
4596 case MM_SETMENUHANDLE
: // wine'isms
4599 PMENU pmenu
= UserGetMenuObject((HMENU
)wParam
);
4602 ERR("Bad Menu Handle\n");
4605 UserReferenceObject(pmenu
);
4606 if (pPopupMenu
->spmenu
)
4608 IntReleaseMenuObject(pPopupMenu
->spmenu
);
4610 pPopupMenu
->spmenu
= pmenu
;
4614 case MM_GETMENUHANDLE
: // wine'isms
4616 *lResult
= (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? UserHMGetHandle(pPopupMenu
->spmenu
) : NULL
) : NULL
);
4620 if (Message
> MN_GETHMENU
&& Message
< MN_GETHMENU
+19)
4622 ERR("Someone is passing unknown menu messages %d\n",Message
);
4624 TRACE("PMWP to IDWP %d\n",Message
);
4625 *lResult
= IntDefWindowProc(Wnd
, Message
, wParam
, lParam
, FALSE
);
4633 IntHiliteMenuItem(PWND WindowObject
,
4639 UINT uItem
= uItemHilite
;
4641 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItem
, uHilite
))) return TRUE
;
4643 if (uHilite
& MF_HILITE
)
4645 MenuItem
->fState
|= MF_HILITE
;
4649 MenuItem
->fState
&= ~MF_HILITE
;
4651 if (MenuObject
->iItem
== uItemHilite
) return TRUE
;
4652 MENU_HideSubPopups( WindowObject
, MenuObject
, FALSE
, 0 );
4653 MENU_SelectItem( WindowObject
, MenuObject
, uItemHilite
, TRUE
, 0 );
4655 return TRUE
; // Always returns true!!!!
4659 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
4663 DWORD dwExStyle
= 0;
4664 BOOLEAN retValue
= TRUE
;
4666 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
4668 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
4670 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
4672 dwStyle
= pWindowObject
->style
;
4673 dwExStyle
= pWindowObject
->ExStyle
;
4675 bti
->rcTitleBar
.top
= 0;
4676 bti
->rcTitleBar
.left
= 0;
4677 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
4678 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
4680 /* Is it iconiced ? */
4681 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
4683 /* Remove frame from rectangle */
4684 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
4686 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4687 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
4689 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
4691 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4692 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
4694 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
4696 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4697 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
4700 /* We have additional border information if the window
4701 * is a child (but not an MDI child) */
4702 if ( (dwStyle
& WS_CHILD
) &&
4703 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
4705 if (dwExStyle
& WS_EX_CLIENTEDGE
)
4707 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4708 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
4711 if (dwExStyle
& WS_EX_STATICEDGE
)
4713 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4714 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
4719 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
4720 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
4721 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
4723 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
4724 if (dwExStyle
& WS_EX_TOOLWINDOW
)
4726 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4727 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
4731 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4732 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
4733 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
4736 if (dwStyle
& WS_CAPTION
)
4738 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
4739 if (dwStyle
& WS_SYSMENU
)
4741 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
4743 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4744 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4748 if (!(dwStyle
& WS_MINIMIZEBOX
))
4750 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
4752 if (!(dwStyle
& WS_MAXIMIZEBOX
))
4754 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
4758 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
4760 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4762 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
4764 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
4769 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
4770 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
4771 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
4772 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
4777 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
4782 EngSetLastError(ERROR_INVALID_PARAMETER
);
4794 LPCMENUITEMINFOW UnsafeItemInfo
,
4795 PUNICODE_STRING lpstr
)
4798 ROSMENUITEMINFO ItemInfo
;
4800 /* Try to copy the whole MENUITEMINFOW structure */
4801 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
4802 if (NT_SUCCESS(Status
))
4804 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
4805 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4807 EngSetLastError(ERROR_INVALID_PARAMETER
);
4810 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4813 /* Try to copy without last field (not present in older versions) */
4814 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
4815 if (NT_SUCCESS(Status
))
4817 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
4819 EngSetLastError(ERROR_INVALID_PARAMETER
);
4822 ItemInfo
.hbmpItem
= (HBITMAP
)0;
4823 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
4826 SetLastNtError(Status
);
4830 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
4835 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4840 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
4842 if (pItem
->spSubMenu
)
4844 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|MF_POPUP
) & 0xff);
4847 return (pItem
->fType
| pItem
->fState
);
4850 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
4855 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
4860 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4862 if (pItem
->spSubMenu
)
4864 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
4870 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
4872 PMENU menu
, pSubTarget
;
4874 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
4875 return NO_SELECTED_ITEM
;
4877 pSubTarget
= UserGetMenuObject(hSubTarget
);
4879 Pos
= MENU_FindSubMenu(&menu
, pSubTarget
);
4881 *hMenu
= (menu
? UserHMGetHandle(menu
) : NULL
);
4887 HMENU FASTCALL
UserCreateMenu(PDESKTOP Desktop
, BOOL PopupMenu
)
4889 PWINSTATION_OBJECT WinStaObject
;
4893 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
4895 if (gpepCSRSS
!= CurrentProcess
)
4898 * gpepCSRSS does not have a Win32WindowStation
4901 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
4907 if (!NT_SUCCESS(Status
))
4909 ERR("Validation of window station handle (%p) failed\n",
4910 CurrentProcess
->Win32WindowStation
);
4911 SetLastNtError(Status
);
4914 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, Desktop
, GetW32ProcessInfo());
4915 if (Menu
&& Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
4917 ERR("Desktop Window Station does not match Process one!\n");
4919 ObDereferenceObject(WinStaObject
);
4923 Menu
= IntCreateMenu(&Handle
, !PopupMenu
, GetW32ThreadInfo()->rpdesk
, GetW32ProcessInfo());
4926 if (Menu
) UserDereferenceObject(Menu
);
4927 return (HMENU
)Handle
;
4935 PROSMENUITEMINFO ItemInfo
,
4937 PUNICODE_STRING lpstr
)
4942 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
4944 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
4949 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
4953 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
4963 PROSMENUITEMINFO UnsafeItemInfo
,
4965 PUNICODE_STRING lpstr
)
4968 ROSMENUITEMINFO ItemInfo
;
4973 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
4974 if (! NT_SUCCESS(Status
))
4976 SetLastNtError(Status
);
4979 if ( Size
!= sizeof(MENUITEMINFOW
) &&
4980 Size
!= FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) &&
4981 Size
!= sizeof(ROSMENUITEMINFO
) )
4983 EngSetLastError(ERROR_INVALID_PARAMETER
);
4986 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
4987 if (! NT_SUCCESS(Status
))
4989 SetLastNtError(Status
);
4992 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
4994 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
4995 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
4997 EngSetLastError(ERROR_INVALID_PARAMETER
);
5001 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
5003 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
5004 if ( SetOrGet
&& Item
== SC_TASKLIST
&& !ByPosition
)
5007 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
5013 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
5017 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
5020 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
5021 if (! NT_SUCCESS(Status
))
5023 SetLastNtError(Status
);
5035 PROSMENUINFO UnsafeMenuInfo
,
5041 ROSMENUINFO MenuInfo
;
5043 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
5044 if (! NT_SUCCESS(Status
))
5046 SetLastNtError(Status
);
5049 if ( Size
< sizeof(MENUINFO
) || Size
> sizeof(ROSMENUINFO
) )
5051 EngSetLastError(ERROR_INVALID_PARAMETER
);
5054 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
5055 if (! NT_SUCCESS(Status
))
5057 SetLastNtError(Status
);
5064 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
5069 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
5072 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
5073 if (! NT_SUCCESS(Status
))
5075 SetLastNtError(Status
);
5095 if ((MenuItem
= MENU_FindItem (&Menu
, &I
, MF_BYPOSITION
)))
5097 Rect
->left
= MenuItem
->xItem
;
5098 Rect
->top
= MenuItem
->yItem
;
5099 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
5100 Rect
->bottom
= MenuItem
->cyItem
;
5104 ERR("Failed Item Lookup! %u\n", uItem
);
5110 HWND hWnd
= Menu
->hWnd
;
5111 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
5114 if (Menu
->fFlags
& MNF_POPUP
)
5116 XMove
= pWnd
->rcClient
.left
;
5117 YMove
= pWnd
->rcClient
.top
;
5121 XMove
= pWnd
->rcWindow
.left
;
5122 YMove
= pWnd
->rcWindow
.top
;
5125 Rect
->left
+= XMove
;
5127 Rect
->right
+= XMove
;
5128 Rect
->bottom
+= YMove
;
5133 PMENU FASTCALL
MENU_GetSystemMenu(PWND Window
, PMENU Popup
)
5135 PMENU Menu
, NewMenu
= NULL
, SysMenu
= NULL
;
5136 HMENU hSysMenu
, hNewMenu
= NULL
;
5137 ROSMENUITEMINFO ItemInfoSet
= {0};
5138 ROSMENUITEMINFO ItemInfo
= {0};
5139 UNICODE_STRING MenuName
;
5141 hSysMenu
= UserCreateMenu(Window
->head
.rpdesk
, FALSE
);
5142 if (NULL
== hSysMenu
)
5146 SysMenu
= UserGetMenuObject(hSysMenu
);
5147 if (NULL
== SysMenu
)
5149 UserDestroyMenu(hSysMenu
);
5153 SysMenu
->fFlags
|= MNF_SYSMENU
;
5154 SysMenu
->hWnd
= UserHMGetHandle(Window
);
5158 //hNewMenu = co_IntLoadSysMenuTemplate();
5159 if ( Window
->ExStyle
& WS_EX_MDICHILD
)
5161 RtlInitUnicodeString( &MenuName
, L
"SYSMENUMDI");
5162 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5166 RtlInitUnicodeString( &MenuName
, L
"SYSMENU");
5167 hNewMenu
= co_IntCallLoadMenu( hModClient
, &MenuName
);
5168 //ERR("%wZ\n",&MenuName);
5173 IntDestroyMenuObject(SysMenu
, FALSE
);
5176 Menu
= UserGetMenuObject(hNewMenu
);
5179 IntDestroyMenuObject(SysMenu
, FALSE
);
5183 // Do the rest in here.
5185 Menu
->fFlags
|= MNS_CHECKORBMP
| MNF_SYSMENU
| MNF_POPUP
;
5187 ItemInfoSet
.cbSize
= sizeof( MENUITEMINFOW
);
5188 ItemInfoSet
.fMask
= MIIM_BITMAP
;
5189 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
5190 IntMenuItemInfo(Menu
, SC_CLOSE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5191 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
5192 IntMenuItemInfo(Menu
, SC_RESTORE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5193 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
5194 IntMenuItemInfo(Menu
, SC_MAXIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5195 ItemInfoSet
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
5196 IntMenuItemInfo(Menu
, SC_MINIMIZE
, FALSE
, &ItemInfoSet
, TRUE
, NULL
);
5198 NewMenu
= IntCloneMenu(Menu
);
5199 if (NewMenu
== NULL
)
5201 IntDestroyMenuObject(Menu
, FALSE
);
5202 IntDestroyMenuObject(SysMenu
, FALSE
);
5206 IntReleaseMenuObject(NewMenu
);
5207 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
5209 IntDestroyMenuObject(Menu
, FALSE
);
5217 NewMenu
->fFlags
|= MNF_SYSMENU
| MNF_POPUP
;
5219 if (Window
->pcls
->style
& CS_NOCLOSE
)
5220 IntRemoveMenuItem(NewMenu
, SC_CLOSE
, MF_BYCOMMAND
, TRUE
);
5222 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
5223 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
5224 ItemInfo
.fType
= MF_POPUP
;
5225 ItemInfo
.fState
= MFS_ENABLED
;
5226 ItemInfo
.dwTypeData
= NULL
;
5228 ItemInfo
.hSubMenu
= UserHMGetHandle(NewMenu
);
5229 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
, NULL
);
5233 ERR("failed to load system menu!\n");
5238 IntGetSystemMenu(PWND Window
, BOOL bRevert
)
5244 if (Window
->SystemMenu
)
5246 Menu
= UserGetMenuObject(Window
->SystemMenu
);
5247 if (Menu
&& !(Menu
->fFlags
& MNF_SYSDESKMN
))
5249 IntDestroyMenuObject(Menu
, TRUE
);
5250 Window
->SystemMenu
= NULL
;
5256 Menu
= Window
->SystemMenu
? UserGetMenuObject(Window
->SystemMenu
) : NULL
;
5257 if ((!Menu
|| Menu
->fFlags
& MNF_SYSDESKMN
) && Window
->style
& WS_SYSMENU
)
5259 Menu
= MENU_GetSystemMenu(Window
, NULL
);
5260 Window
->SystemMenu
= Menu
? UserHMGetHandle(Menu
) : NULL
;
5264 if (Window
->SystemMenu
)
5266 HMENU hMenu
= IntGetSubMenu( Window
->SystemMenu
, 0);
5267 /* Store the dummy sysmenu handle to facilitate the refresh */
5268 /* of the close button if the SC_CLOSE item change */
5269 Menu
= UserGetMenuObject(hMenu
);
5272 Menu
->spwndNotify
= Window
;
5273 Menu
->fFlags
|= MNF_SYSSUBMENU
;
5281 IntSetSystemMenu(PWND Window
, PMENU Menu
)
5285 if (!(Window
->style
& WS_SYSMENU
)) return FALSE
;
5287 if (Window
->SystemMenu
)
5289 OldMenu
= UserGetMenuObject(Window
->SystemMenu
);
5292 OldMenu
->fFlags
&= ~MNF_SYSMENU
;
5293 IntDestroyMenuObject(OldMenu
, TRUE
);
5297 OldMenu
= MENU_GetSystemMenu(Window
, Menu
);
5299 { // Use spmenuSys too!
5300 Window
->SystemMenu
= UserHMGetHandle(OldMenu
);
5303 Window
->SystemMenu
= NULL
;
5305 if (Menu
&& Window
!= Menu
->spwndNotify
)
5307 Menu
->spwndNotify
= Window
;
5319 PMENU OldMenu
, NewMenu
= NULL
;
5321 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
5323 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd
));
5324 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5328 *Changed
= (UlongToHandle(Wnd
->IDMenu
) != Menu
);
5336 OldMenu
= IntGetMenuObject(UlongToHandle(Wnd
->IDMenu
));
5337 ASSERT(NULL
== OldMenu
|| OldMenu
->hWnd
== UserHMGetHandle(Wnd
));
5346 NewMenu
= IntGetMenuObject(Menu
);
5347 if (NULL
== NewMenu
)
5349 if (NULL
!= OldMenu
)
5351 IntReleaseMenuObject(OldMenu
);
5353 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5356 if (NULL
!= NewMenu
->hWnd
)
5358 /* Can't use the same menu for two windows */
5359 if (NULL
!= OldMenu
)
5361 IntReleaseMenuObject(OldMenu
);
5363 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5369 Wnd
->IDMenu
= (UINT_PTR
) Menu
;
5370 if (NULL
!= NewMenu
)
5372 NewMenu
->hWnd
= UserHMGetHandle(Wnd
);
5373 IntReleaseMenuObject(NewMenu
);
5375 if (NULL
!= OldMenu
)
5377 OldMenu
->hWnd
= NULL
;
5378 IntReleaseMenuObject(OldMenu
);
5385 /* FUNCTIONS *****************************************************************/
5390 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5405 UserEnterExclusive();
5407 if(!(Window
= UserGetWindowObject(hwnd
)))
5409 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5414 hdc
= UserGetDCEx(NULL
, NULL
, DCX_CACHE
);
5421 Rect
.left
= leftBorder
;
5422 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
5426 ret
= MENU_DrawMenuBar(hdc
, &Rect
, Window
, TRUE
);
5428 UserReleaseDC( 0, hdc
, FALSE
);
5439 NtUserCheckMenuItem(
5445 DECLARE_RETURN(DWORD
);
5447 TRACE("Enter NtUserCheckMenuItem\n");
5448 UserEnterExclusive();
5450 if(!(Menu
= UserGetMenuObject(hMenu
)))
5455 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
5458 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
5473 DECLARE_RETURN(BOOL
);
5475 TRACE("Enter NtUserDeleteMenu\n");
5476 UserEnterExclusive();
5478 if(!(Menu
= UserGetMenuObject(hMenu
)))
5483 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
5486 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
5492 * NtUserGetSystemMenu
5494 * The NtUserGetSystemMenu function allows the application to access the
5495 * window menu (also known as the system menu or the control menu) for
5496 * copying and modifying.
5500 * Handle to the window that will own a copy of the window menu.
5502 * Specifies the action to be taken. If this parameter is FALSE,
5503 * NtUserGetSystemMenu returns a handle to the copy of the window menu
5504 * currently in use. The copy is initially identical to the window menu
5505 * but it can be modified.
5506 * If this parameter is TRUE, GetSystemMenu resets the window menu back
5507 * to the default state. The previous window menu, if any, is destroyed.
5510 * If the bRevert parameter is FALSE, the return value is a handle to a
5511 * copy of the window menu. If the bRevert parameter is TRUE, the return
5519 NtUserGetSystemMenu(HWND hWnd
, BOOL bRevert
)
5523 DECLARE_RETURN(HMENU
);
5525 TRACE("Enter NtUserGetSystemMenu\n");
5526 UserEnterExclusive();
5528 if (!(Window
= UserGetWindowObject(hWnd
)))
5533 if (!(Menu
= IntGetSystemMenu(Window
, bRevert
)))
5538 RETURN(Menu
->head
.h
);
5541 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_
);
5547 * NtUserSetSystemMenu
5554 NtUserSetSystemMenu(HWND hWnd
, HMENU hMenu
)
5556 BOOL Result
= FALSE
;
5559 DECLARE_RETURN(BOOL
);
5561 TRACE("Enter NtUserSetSystemMenu\n");
5562 UserEnterExclusive();
5564 if (!(Window
= UserGetWindowObject(hWnd
)))
5572 * Assign new menu handle and Up the Lock Count.
5574 if (!(Menu
= IntGetMenuObject(hMenu
)))
5579 Result
= IntSetSystemMenu(Window
, Menu
);
5582 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5587 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_
);
5596 NtUserGetTitleBarInfo(
5601 TITLEBARINFO bartitleinfo
;
5602 DECLARE_RETURN(BOOLEAN
);
5603 BOOLEAN retValue
= TRUE
;
5605 TRACE("Enter NtUserGetTitleBarInfo\n");
5606 UserEnterExclusive();
5608 /* Vaildate the windows handle */
5609 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
5611 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5617 /* Copy our usermode buffer bti to local buffer bartitleinfo */
5618 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
5619 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
5621 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5623 /* Fail copy the data */
5624 EngSetLastError(ERROR_INVALID_PARAMETER
);
5629 /* Get the tile bar info */
5632 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
5637 /* Copy our buffer to user mode buffer bti */
5638 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
5639 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
5641 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5643 /* Fail copy the data */
5644 EngSetLastError(ERROR_INVALID_PARAMETER
);
5654 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
5662 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
5665 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
5667 if(!(Menu
= UserGetMenuObject(hMenu
)))
5672 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
5674 EngSetLastError(ERROR_ACCESS_DENIED
);
5677 return IntDestroyMenuObject(Menu
, FALSE
);
5688 DECLARE_RETURN(BOOL
);
5690 TRACE("Enter NtUserDestroyMenu\n");
5691 UserEnterExclusive();
5693 if(!(Menu
= UserGetMenuObject(hMenu
)))
5697 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
5699 EngSetLastError(ERROR_ACCESS_DENIED
);
5702 RETURN( IntDestroyMenuObject(Menu
, TRUE
));
5705 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
5714 NtUserEnableMenuItem(
5720 DECLARE_RETURN(UINT
);
5722 TRACE("Enter NtUserEnableMenuItem\n");
5723 UserEnterExclusive();
5725 if(!(Menu
= UserGetMenuObject(hMenu
)))
5730 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
5733 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
5745 TRACE("Enter NtUserEndMenu\n");
5746 UserEnterExclusive();
5747 /* if ( gptiCurrent->pMenuState &&
5748 gptiCurrent->pMenuState->pGlobalPopupMenu )
5750 pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5753 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5756 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5758 if (fInsideMenuLoop
&& top_popup
)
5760 fInsideMenuLoop
= FALSE
;
5761 UserPostMessage( top_popup
, WM_CANCELMODE
, 0, 0);
5764 TRACE("Leave NtUserEndMenu\n");
5772 NtUserGetMenuBarInfo(
5782 PPOPUPMENU pPopupMenu
;
5783 USER_REFERENCE_ENTRY Ref
;
5784 NTSTATUS Status
= STATUS_SUCCESS
;
5786 DECLARE_RETURN(BOOL
);
5788 TRACE("Enter NtUserGetMenuBarInfo\n");
5791 if (!(pWnd
= UserGetWindowObject(hwnd
)))
5793 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5797 UserRefObjectCo(pWnd
, &Ref
);
5799 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
5801 kmbi
.hwndMenu
= NULL
;
5802 kmbi
.fBarFocused
= FALSE
;
5803 kmbi
.fFocused
= FALSE
;
5808 if (!pWnd
->pcls
->fnid
)
5810 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
5812 WARN("called on invalid window: %u\n", pWnd
->pcls
->fnid
);
5813 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
5816 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5817 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
5818 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
5819 if (pPopupMenu
&& pPopupMenu
->spmenu
)
5821 if (UserHMGetHandle(pPopupMenu
->spmenu
) != hMenu
)
5823 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu
->spmenu
->head
.h
,hMenu
);
5828 if (pWnd
->style
& WS_CHILD
) RETURN(FALSE
);
5829 hMenu
= UlongToHandle(pWnd
->IDMenu
);
5830 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu
);
5833 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
5834 Menu
= IntGetSystemMenu(pWnd
, FALSE
);
5835 hMenu
= UserHMGetHandle(Menu
);
5846 ProbeForRead(pmbi
, sizeof(MENUBARINFO
), 1);
5847 kmbi
.cbSize
= pmbi
->cbSize
;
5849 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5855 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
5857 EngSetLastError(ERROR_INVALID_PARAMETER
);
5861 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
5865 if ((idItem
< 0) || ((ULONG
)idItem
> Menu
->cItems
))
5870 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
5871 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
5872 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
5873 TRACE("idItem a 0 %d\n",Ret
);
5877 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
5878 TRACE("idItem b %d %d\n", idItem
-1, Ret
);
5882 kmbi
.fBarFocused
= top_popup_hmenu
== hMenu
;
5883 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu
, hMenu
);
5886 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
5887 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
5889 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
5894 kmbi
.fFocused
= kmbi
.fBarFocused
;
5899 ProbeForWrite(pmbi
, sizeof(MENUBARINFO
), 1);
5900 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
5902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5904 Status
= _SEH2_GetExceptionCode();
5908 if (!NT_SUCCESS(Status
))
5910 SetLastNtError(Status
);
5917 if (pWnd
) UserDerefObjectCo(pWnd
);
5918 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
5931 PMENU Menu
, SubMenu
;
5934 DECLARE_RETURN(UINT
);
5936 TRACE("Enter NtUserGetMenuIndex\n");
5939 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
5940 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
5943 MenuItem
= Menu
->rgItems
;
5944 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
5946 if (MenuItem
->spSubMenu
== SubMenu
)
5947 RETURN(MenuItem
->wID
);
5952 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
5961 NtUserGetMenuItemRect(
5972 NTSTATUS Status
= STATUS_SUCCESS
;
5973 DECLARE_RETURN(BOOL
);
5975 TRACE("Enter NtUserGetMenuItemRect\n");
5978 if (!(Menu
= UserGetMenuObject(hMenu
)))
5983 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
5985 Rect
.left
= MenuItem
->xItem
;
5986 Rect
.top
= MenuItem
->yItem
;
5987 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
5988 Rect
.bottom
= MenuItem
->cyItem
;
5998 if (lprcItem
== NULL
) RETURN( FALSE
);
6000 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
6002 if (Menu
->fFlags
& MNF_POPUP
)
6004 XMove
= ReferenceWnd
->rcClient
.left
;
6005 YMove
= ReferenceWnd
->rcClient
.top
;
6009 XMove
= ReferenceWnd
->rcWindow
.left
;
6010 YMove
= ReferenceWnd
->rcWindow
.top
;
6015 Rect
.right
+= XMove
;
6016 Rect
.bottom
+= YMove
;
6020 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
6022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6024 Status
= _SEH2_GetExceptionCode();
6028 if (!NT_SUCCESS(Status
))
6030 SetLastNtError(Status
);
6036 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
6045 NtUserHiliteMenuItem(
6053 DECLARE_RETURN(BOOLEAN
);
6055 TRACE("Enter NtUserHiliteMenuItem\n");
6056 UserEnterExclusive();
6058 if(!(Window
= UserGetWindowObject(hWnd
)))
6060 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6064 if(!(Menu
= UserGetMenuObject(hMenu
)))
6066 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6070 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
6073 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
6083 NtUserDrawMenuBarTemp(
6093 NTSTATUS Status
= STATUS_SUCCESS
;
6094 DECLARE_RETURN(DWORD
);
6096 ERR("Enter NtUserDrawMenuBarTemp\n");
6097 UserEnterExclusive();
6099 if(!(Window
= UserGetWindowObject(hWnd
)))
6101 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6105 if(!(Menu
= UserGetMenuObject(hMenu
)))
6107 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
6113 ProbeForRead(pRect
, sizeof(RECT
), sizeof(ULONG
));
6114 RtlCopyMemory(&Rect
, pRect
, sizeof(RECT
));
6116 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6118 Status
= _SEH2_GetExceptionCode();
6122 if (Status
!= STATUS_SUCCESS
)
6124 SetLastNtError(Status
);
6128 RETURN( IntDrawMenuBarTemp(Window
, hDC
, &Rect
, Menu
, hFont
));
6131 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_
);
6140 NtUserMenuItemFromPoint(
6150 DECLARE_RETURN(int);
6152 TRACE("Enter NtUserMenuItemFromPoint\n");
6153 UserEnterExclusive();
6155 if (!(Menu
= UserGetMenuObject(hMenu
)))
6160 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
6165 X
-= Window
->rcWindow
.left
;
6166 Y
-= Window
->rcWindow
.top
;
6169 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
6173 Rect
.left
= mi
->xItem
;
6174 Rect
.top
= mi
->yItem
;
6175 Rect
.right
= mi
->cxItem
;
6176 Rect
.bottom
= mi
->cyItem
;
6178 MENU_AdjustMenuItemRect(Menu
, &Rect
);
6180 if (RECTL_bPointInRect(&Rect
, X
, Y
))
6186 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
6189 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
6209 UserEnterExclusive();
6211 if(!(Window
= UserGetWindowObject(hWnd
)))
6213 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
6218 Rect
.left
= leftBorder
;
6219 Rect
.right
= Window
->rcWindow
.right
- Window
->rcWindow
.left
- rightBorder
;
6223 ret
= MENU_DrawMenuBar(hDC
, &Rect
, Window
, FALSE
);
6240 DECLARE_RETURN(BOOL
);
6242 TRACE("Enter NtUserRemoveMenu\n");
6243 UserEnterExclusive();
6245 if(!(Menu
= UserGetMenuObject(hMenu
)))
6250 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
6253 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
6270 DECLARE_RETURN(BOOL
);
6272 TRACE("Enter NtUserSetMenu\n");
6273 UserEnterExclusive();
6275 if (!(Window
= UserGetWindowObject(hWnd
)))
6280 if (!IntSetMenu(Window
, Menu
, &Changed
))
6285 // Not minimized and please repaint!!!
6286 if (!(Window
->style
& WS_MINIMIZE
) && (Repaint
|| Changed
))
6288 USER_REFERENCE_ENTRY Ref
;
6289 UserRefObjectCo(Window
, &Ref
);
6290 co_WinPosSetWindowPos(Window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
6291 UserDerefObjectCo(Window
);
6297 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_
);
6306 NtUserSetMenuContextHelpId(
6308 DWORD dwContextHelpId
)
6311 DECLARE_RETURN(BOOL
);
6313 TRACE("Enter NtUserSetMenuContextHelpId\n");
6314 UserEnterExclusive();
6316 if(!(Menu
= UserGetMenuObject(hMenu
)))
6321 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
6324 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
6333 NtUserSetMenuDefaultItem(
6339 DECLARE_RETURN(BOOL
);
6341 TRACE("Enter NtUserSetMenuDefaultItem\n");
6342 UserEnterExclusive();
6344 if(!(Menu
= UserGetMenuObject(hMenu
)))
6349 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
6352 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
6361 NtUserSetMenuFlagRtoL(
6365 DECLARE_RETURN(BOOL
);
6367 TRACE("Enter NtUserSetMenuFlagRtoL\n");
6368 UserEnterExclusive();
6370 if(!(Menu
= UserGetMenuObject(hMenu
)))
6375 RETURN(IntSetMenuFlagRtoL(Menu
));
6378 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
6387 NtUserThunkedMenuInfo(
6392 DECLARE_RETURN(BOOL
);
6394 TRACE("Enter NtUserThunkedMenuInfo\n");
6395 UserEnterExclusive();
6397 if (!(Menu
= UserGetMenuObject(hMenu
)))
6402 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
6405 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
6414 NtUserThunkedMenuItemInfo(
6419 LPMENUITEMINFOW lpmii
,
6420 PUNICODE_STRING lpszCaption
)
6424 UNICODE_STRING lstrCaption
;
6425 DECLARE_RETURN(BOOL
);
6427 TRACE("Enter NtUserThunkedMenuItemInfo\n");
6428 UserEnterExclusive();
6430 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6431 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
6433 RtlInitEmptyUnicodeString(&lstrCaption
, NULL
, 0);
6435 if (!(Menu
= UserGetMenuObject(hMenu
)))
6440 /* Check if we got a Caption */
6441 if (lpszCaption
&& lpszCaption
->Buffer
)
6443 /* Copy the string to kernel mode */
6444 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
6447 if (!NT_SUCCESS(Status
))
6449 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
6450 SetLastNtError(Status
);
6455 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
6457 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
6460 if (lstrCaption
.Buffer
)
6462 ReleaseCapturedUnicodeString(&lstrCaption
, UserMode
);
6465 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);
6474 NtUserTrackPopupMenuEx(
6486 USER_REFERENCE_ENTRY Ref
;
6488 TRACE("Enter NtUserTrackPopupMenuEx\n");
6489 UserEnterExclusive();
6490 /* Parameter check */
6491 if (!(menu
= UserGetMenuObject( hMenu
)))
6493 ERR("TPME : Invalid Menu handle.\n");
6494 EngSetLastError( ERROR_INVALID_MENU_HANDLE
);
6498 if (!(pWnd
= UserGetWindowObject(hWnd
)))
6500 ERR("TPME : Invalid Window handle.\n");
6508 ProbeForRead(lptpm
, sizeof(TPMPARAMS
), sizeof(ULONG
));
6511 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
6513 _SEH2_YIELD(goto Exit
);
6517 UserRefObjectCo(pWnd
, &Ref
);
6518 Ret
= IntTrackPopupMenuEx(menu
, fuFlags
, x
, y
, pWnd
, lptpm
? &tpm
: NULL
);
6519 UserDerefObjectCo(pWnd
);
6522 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret
);