2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: user32/windows/menu.c
7 * PROGRAMMERS: Casper S. Hornstrup
11 /* INCLUDES ******************************************************************/
14 #include <wine/debug.h>
16 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
17 BOOL WINAPI
GdiValidateHandle(HGDIOBJ hobj
);
19 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
21 /* internal popup menu window messages */
23 #define MM_SETMENUHANDLE (WM_USER + 0)
24 #define MM_GETMENUHANDLE (WM_USER + 1)
26 /* internal flags for menu tracking */
28 #define TF_ENDMENU 0x10000
29 #define TF_SUSPENDPOPUP 0x20000
30 #define TF_SKIPREMOVE 0x40000
35 /* Internal MenuTrackMenu() flags */
36 #define TPM_INTERNAL 0xF0000000
37 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
38 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
40 /* top and bottom margins for popup menus */
41 #define MENU_TOP_MARGIN 3
42 #define MENU_BOTTOM_MARGIN 2
44 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
46 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
48 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
50 #define MENUITEMINFO_TYPE_MASK \
51 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
52 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
53 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
55 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
57 #define STATE_MASK (~TYPE_MASK)
59 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
61 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
63 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
64 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
65 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
67 #define IS_SYSTEM_MENU(MenuInfo) \
68 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
70 #define IS_SYSTEM_POPUP(MenuInfo) \
71 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
73 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
75 /* Use global popup window because there's no way 2 menus can
76 * be tracked at the same time. */
77 static HWND top_popup
;
78 static HMENU top_popup_hmenu
;
80 /* Flag set by EndMenu() to force an exit from menu tracking */
81 static BOOL fEndMenu
= FALSE
;
83 #define MENU_ITEM_HBMP_SPACE (5)
84 #define MENU_BAR_ITEMS_SPACE (12)
85 #define SEPARATOR_HEIGHT (5)
86 #define MENU_TAB_SPACE (8)
91 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
92 HMENU TopMenu
; /* initial menu */
93 HWND OwnerWnd
; /* where notifications are sent */
98 /*********************************************************************
99 * PopupMenu class descriptor
101 const struct builtin_class_descr POPUPMENU_builtin_class
=
104 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
105 (WNDPROC
) NULL
, /* FIXME - procA */
106 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
107 sizeof(MENUINFO
*), /* extra */
108 (LPCWSTR
) IDC_ARROW
, /* cursor */
109 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
113 #define GET_WORD(ptr) (*(WORD *)(ptr))
116 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
119 HFONT hMenuFont
= NULL
;
120 HFONT hMenuFontBold
= NULL
;
122 /* Dimension of the menu bitmaps */
123 static HBITMAP BmpSysMenu
= NULL
;
125 static SIZE MenuCharSize
;
128 /***********************************************************************
131 * Validate the given menu handle and returns the menu structure pointer.
133 PMENU FORCEINLINE
MENU_GetMenu(HMENU hMenu
)
135 return ValidateHandle(hMenu
, TYPE_MENU
);
138 /***********************************************************************
141 * Find a menu item. Return a pointer on the item, and modifies *hmenu
142 * in case the item was in a sub-menu.
144 ITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
147 ITEM
*fallback
= NULL
;
148 UINT fallback_pos
= 0;
152 if ((*hmenu
== (HMENU
)0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
153 if (wFlags
& MF_BYPOSITION
)
155 if (*nPos
>= menu
->cItems
) return NULL
;
156 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
157 //pItem = &menu->rgItems[*nPos];
159 while(pItem
) // Do this for now.
161 if (i
< (INT
)menu
->cItems
)
163 if ( *nPos
== i
) return pItem
;
165 pItem
= pItem
->Next
? DesktopPtrToUser(pItem
->Next
) : NULL
;
171 PITEM item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
172 for (i
= 0; item
,i
< menu
->cItems
; i
++, item
= item
->Next
? DesktopPtrToUser(item
->Next
) : NULL
)//, item++)
176 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
177 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
178 ITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
184 else if (item
->wID
== *nPos
)
186 /* fallback to this item if nothing else found */
191 else if (item
->wID
== *nPos
)
200 *nPos
= fallback_pos
;
205 #define MAX_GOINTOSUBMENU (0x10)
207 IntGetMenuDefaultItem(PMENU Menu
, BOOL fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
212 PITEM Item
= Menu
->rgItems
? DesktopPtrToUser(Menu
->rgItems
) : NULL
;
216 if (Item
->fState
& MFS_DEFAULT
)
218 if (!(gmdiFlags
& GMDI_USEDISABLED
) &&
219 (Item
->fState
& MFS_DISABLED
) )
222 res
= fByPos
? x
: Item
->wID
;
224 if ((*gismc
< MAX_GOINTOSUBMENU
) &&
225 (gmdiFlags
& GMDI_GOINTOPOPUPS
) &&
228 if (DesktopPtrToUser(Item
->spSubMenu
) == Menu
)
232 sres
= IntGetMenuDefaultItem( DesktopPtrToUser(Item
->spSubMenu
), fByPos
, gmdiFlags
, gismc
);
240 Item
= Item
->Next
? DesktopPtrToUser(Item
->Next
) : NULL
;
246 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
,
249 LPMENUITEMINFOW lpmii
,
252 ITEM
*pItem
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
254 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
258 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
259 //SetLastError(ERROR_INVALID_PARAMETER);
263 if( lpmii
->fMask
& MIIM_TYPE
)
265 if( lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
267 ERR("invalid combination of fMask bits used\n");
268 /* this does not happen on Win9x/ME */
269 SetLastError( ERROR_INVALID_PARAMETER
);
272 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
273 if( pItem
->hbmp
) lpmii
->fType
|= MFT_BITMAP
;
274 lpmii
->hbmpItem
= pItem
->hbmp
; /* not on Win9x/ME */
275 if( lpmii
->fType
& MFT_BITMAP
)
277 lpmii
->dwTypeData
= (LPWSTR
) pItem
->hbmp
;
280 else if( lpmii
->fType
& (MFT_OWNERDRAW
| MFT_SEPARATOR
))
282 /* this does not happen on Win9x/ME */
283 lpmii
->dwTypeData
= 0;
288 /* copy the text string */
289 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)))
292 { // Very strange this fixes a wine test with a crash.
293 if(lpmii
->dwTypeData
&& lpmii
->cch
&& !(GdiValidateHandle((HGDIOBJ
)lpmii
->dwTypeData
)) )
297 *((WCHAR
*)lpmii
->dwTypeData
) = 0;
299 *((CHAR
*)lpmii
->dwTypeData
) = 0;
305 LPWSTR text
= DesktopPtrToUser(pItem
->Xlpstr
);
309 if(lpmii
->dwTypeData
&& lpmii
->cch
)
310 lstrcpynW(lpmii
->dwTypeData
, text
, lpmii
->cch
);
314 len
= WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
) - 1;
315 if(lpmii
->dwTypeData
&& lpmii
->cch
)
316 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1,
317 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
318 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
- 1] = 0;
320 /* if we've copied a substring we return its length */
321 if(lpmii
->dwTypeData
&& lpmii
->cch
)
322 if (lpmii
->cch
<= len
+ 1)
328 /* return length of string */
329 /* not on Win9x/ME if fType & MFT_BITMAP */
335 if (lpmii
->fMask
& MIIM_FTYPE
)
336 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
338 if (lpmii
->fMask
& MIIM_BITMAP
)
339 lpmii
->hbmpItem
= pItem
->hbmp
;
341 if (lpmii
->fMask
& MIIM_STATE
)
342 lpmii
->fState
= pItem
->fState
& MII_STATE_MASK
; //MENUITEMINFO_STATE_MASK;
344 if (lpmii
->fMask
& MIIM_ID
)
345 lpmii
->wID
= pItem
->wID
;
347 if (lpmii
->fMask
& MIIM_SUBMENU
&& pItem
->spSubMenu
)
349 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
350 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
351 lpmii
->hSubMenu
= hSubMenu
;
355 /* hSubMenu is always cleared
356 * (not on Win9x/ME ) */
360 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
362 lpmii
->hbmpChecked
= pItem
->hbmpChecked
;
363 lpmii
->hbmpUnchecked
= pItem
->hbmpUnchecked
;
365 if (lpmii
->fMask
& MIIM_DATA
)
366 lpmii
->dwItemData
= pItem
->dwItemData
;
371 /***********************************************************************
374 * Get full information about menu
377 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
380 if (!(pMenu
= ValidateHandle(Menu
, TYPE_MENU
))) return FALSE
;
382 MenuInfo
->hbrBack
= pMenu
->hbrBack
;
383 MenuInfo
->dwContextHelpID
= pMenu
->dwContextHelpId
;
384 MenuInfo
->cyMax
= pMenu
->cyMax
;
385 MenuInfo
->dwMenuData
= pMenu
->dwMenuData
;
386 MenuInfo
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
388 MenuInfo
->cItems
= pMenu
->cItems
;
390 MenuInfo
->iItem
= pMenu
->iItem
;
391 MenuInfo
->cxMenu
= pMenu
->cxMenu
;
392 MenuInfo
->cyMenu
= pMenu
->cyMenu
;
393 MenuInfo
->spwndNotify
= pMenu
->spwndNotify
;
394 MenuInfo
->cxTextAlign
= pMenu
->cxTextAlign
;
395 MenuInfo
->iTop
= pMenu
->iMaxTop
;
396 MenuInfo
->iMaxTop
= pMenu
->iMaxTop
;
397 MenuInfo
->dwArrowsOn
= pMenu
->dwArrowsOn
;
399 MenuInfo
->fFlags
= pMenu
->fFlags
;
400 MenuInfo
->Self
= pMenu
->head
.h
;
401 MenuInfo
->TimeToHide
= pMenu
->TimeToHide
;
402 MenuInfo
->Wnd
= pMenu
->hWnd
;
406 /***********************************************************************
409 * Set full information about menu
412 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
414 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
415 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
417 return NtUserThunkedMenuInfo(MenuInfo
->Self
, (LPCMENUINFO
)MenuInfo
);
420 /***********************************************************************
421 * MenuInitRosMenuItemInfo
423 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
426 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
428 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
429 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
432 /***********************************************************************
433 * MenuGetRosMenuItemInfo
435 * Get full information about a menu item
438 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
441 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
443 if (ItemInfo
->dwTypeData
!= NULL
)
445 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
448 ItemInfo
->dwTypeData
= NULL
;
450 if (!(pItem
= MENU_FindItem(&Menu
, &Index
, MF_BYPOSITION
)))
456 ItemInfo
->fType
= pItem
->fType
;
457 ItemInfo
->hbmpItem
= pItem
->hbmp
;
458 ItemInfo
->hbmpChecked
= pItem
->hbmpChecked
;
459 ItemInfo
->hbmpUnchecked
= pItem
->hbmpUnchecked
;
460 ItemInfo
->dwItemData
= pItem
->dwItemData
;
461 ItemInfo
->wID
= pItem
->wID
;
462 ItemInfo
->fState
= pItem
->fState
;
464 if (pItem
->spSubMenu
)
466 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
467 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
468 ItemInfo
->hSubMenu
= hSubMenu
;
471 ItemInfo
->hSubMenu
= NULL
;
473 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
475 LPWSTR lpstr
= pItem
->lpstr
.Buffer
? DesktopPtrToUser(pItem
->lpstr
.Buffer
) : NULL
;
478 ItemInfo
->cch
= pItem
->lpstr
.Length
/ sizeof(WCHAR
);
480 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0, ItemInfo
->cch
* sizeof(WCHAR
));
481 if (ItemInfo
->dwTypeData
== NULL
)
485 RtlCopyMemory(ItemInfo
->dwTypeData
, lpstr
, min(ItemInfo
->cch
* sizeof(WCHAR
), pItem
->lpstr
.MaximumLength
));
493 ItemInfo
->Rect
.left
= pItem
->xItem
;
494 ItemInfo
->Rect
.top
= pItem
->yItem
;
495 ItemInfo
->Rect
.right
= pItem
->cxItem
; // Do this for now......
496 ItemInfo
->Rect
.bottom
= pItem
->cyItem
;
497 ItemInfo
->dxTab
= pItem
->dxTab
;
498 ItemInfo
->lpstr
= pItem
->lpstr
.Buffer
;
499 ItemInfo
->maxBmpSize
.cx
= pItem
->cxBmp
;
500 ItemInfo
->maxBmpSize
.cy
= pItem
->cyBmp
;
502 ItemInfo
->fMask
= Save_Mask
;
506 /***********************************************************************
507 * MenuSetRosMenuItemInfo
509 * Set selected information about a menu item, need to set the mask bits.
512 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
516 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
517 ItemInfo
->dwTypeData
!= NULL
)
519 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
521 Ret
= NtUserThunkedMenuItemInfo(Menu
, Index
, TRUE
, FALSE
, (LPMENUITEMINFOW
)ItemInfo
, NULL
);
525 /***********************************************************************
526 * MenuCleanupRosMenuItemInfo
528 * Cleanup after use of MenuGet/SetRosMenuItemInfo
531 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
533 if (ItemInfo
->dwTypeData
!= NULL
)
535 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
536 ItemInfo
->dwTypeData
= NULL
;
541 IntBuildMenuItemList(PMENU MenuObject
, PVOID Buffer
, ULONG nMax
)
546 PITEM CurItem
= MenuObject
->rgItems
? DesktopPtrToUser(MenuObject
->rgItems
) : NULL
;
552 if (nMax
< MenuObject
->cItems
* sizeof(ROSMENUITEMINFO
))
556 StrOut
= (PWCHAR
)((char *) Buffer
+ MenuObject
->cItems
* sizeof(ROSMENUITEMINFO
));
557 nMax
-= MenuObject
->cItems
* sizeof(ROSMENUITEMINFO
);
559 mii
.cbSize
= sizeof(ROSMENUITEMINFO
);
563 while (NULL
!= CurItem
)
565 mii
.cch
= CurItem
->lpstr
.Length
/ sizeof(WCHAR
);
566 mii
.dwItemData
= CurItem
->dwItemData
;
567 if (0 != CurItem
->lpstr
.Length
)
569 mii
.dwTypeData
= StrOut
;
573 mii
.dwTypeData
= NULL
;
575 mii
.fState
= CurItem
->fState
;
576 mii
.fType
= CurItem
->fType
;
577 mii
.wID
= CurItem
->wID
;
578 mii
.hbmpChecked
= CurItem
->hbmpChecked
;
579 mii
.hbmpItem
= CurItem
->hbmp
;
580 mii
.hbmpUnchecked
= CurItem
->hbmpUnchecked
;
581 if (CurItem
->spSubMenu
)
583 PMENU pSubMenu
= DesktopPtrToUser(CurItem
->spSubMenu
);
584 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
585 mii
.hSubMenu
= hSubMenu
;
589 mii
.Rect
.left
= CurItem
->xItem
;
590 mii
.Rect
.top
= CurItem
->yItem
;
591 mii
.Rect
.right
= CurItem
->cxItem
; // Do this for now......
592 mii
.Rect
.bottom
= CurItem
->cyItem
;
593 mii
.dxTab
= CurItem
->dxTab
;
594 mii
.lpstr
= CurItem
->lpstr
.Buffer
; // Can be read from user side!
595 //mii.maxBmpSize.cx = CurItem->cxBmp;
596 //mii.maxBmpSize.cy = CurItem->cyBmp;
598 RtlCopyMemory(Buf
, &mii
, sizeof(ROSMENUITEMINFO
));
599 Buf
= (PVOID
)((ULONG_PTR
)Buf
+ sizeof(ROSMENUITEMINFO
));
601 if (0 != CurItem
->lpstr
.Length
&& (nMax
>= CurItem
->lpstr
.Length
+ sizeof(WCHAR
)))
603 LPWSTR lpstr
= CurItem
->lpstr
.Buffer
? DesktopPtrToUser(CurItem
->lpstr
.Buffer
) : NULL
;
607 RtlCopyMemory(StrOut
, lpstr
, CurItem
->lpstr
.Length
);
609 StrOut
+= CurItem
->lpstr
.Length
/ sizeof(WCHAR
);
610 RtlCopyMemory(StrOut
, &NulByte
, sizeof(WCHAR
));
612 nMax
-= CurItem
->lpstr
.Length
+ sizeof(WCHAR
);
615 else if (0 != CurItem
->lpstr
.Length
)
620 CurItem
= CurItem
->Next
? DesktopPtrToUser(CurItem
->Next
) : NULL
;
626 while (NULL
!= CurItem
)
628 res
+= sizeof(ROSMENUITEMINFO
) + CurItem
->lpstr
.Length
+ sizeof(WCHAR
);
629 CurItem
= CurItem
->Next
? DesktopPtrToUser(CurItem
->Next
) : NULL
;
635 /***********************************************************************
636 * MenuGetAllRosMenuItemInfo
638 * Get full information about all menu items
641 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
646 if (!(pMenu
= ValidateHandle(Menu
, TYPE_MENU
))) return -1;
648 BufSize
= IntBuildMenuItemList(pMenu
, (PVOID
)1, 0);
649 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
653 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
654 if (NULL
== *ItemInfo
)
659 return IntBuildMenuItemList(pMenu
, (PVOID
)*ItemInfo
, BufSize
);
662 /***********************************************************************
663 * MenuCleanupAllRosMenuItemInfo
665 * Cleanup after use of MenuGetAllRosMenuItemInfo
668 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
670 HeapFree(GetProcessHeap(), 0, ItemInfo
);
673 /***********************************************************************
674 * MenuInitSysMenuPopup
676 * Grey the appropriate items in System menu.
678 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
686 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
687 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
688 gray
= ((style
& WS_MAXIMIZE
) != 0);
689 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
690 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
691 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
692 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
693 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
694 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
695 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
696 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
698 /* The menu item must keep its state if it's disabled */
700 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
702 /* Set default menu item */
703 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
704 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
705 else DefItem
= SC_CLOSE
;
707 mii
.cbSize
= sizeof(MENUITEMINFOW
);
708 mii
.fMask
|= MIIM_STATE
;
709 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
710 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
712 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
715 /******************************************************************************
717 * UINT MenuGetStartOfNextColumn(
718 * PROSMENUINFO MenuInfo)
720 *****************************************************************************/
721 static UINT
MenuGetStartOfNextColumn(
722 PROSMENUINFO MenuInfo
)
724 PROSMENUITEMINFO MenuItems
;
728 if ( i
== NO_SELECTED_ITEM
)
731 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
732 return NO_SELECTED_ITEM
;
734 for (i
++ ; i
< MenuInfo
->cItems
; i
++)
735 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
738 return NO_SELECTED_ITEM
;
741 /******************************************************************************
743 * UINT MenuGetStartOfPrevColumn(
744 * PROSMENUINFO MenuInfo)
746 *****************************************************************************/
748 static UINT FASTCALL
MenuGetStartOfPrevColumn(
749 PROSMENUINFO MenuInfo
)
751 PROSMENUITEMINFO MenuItems
;
754 if (!MenuInfo
->iItem
|| MenuInfo
->iItem
== NO_SELECTED_ITEM
)
755 return NO_SELECTED_ITEM
;
757 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
758 return NO_SELECTED_ITEM
;
760 /* Find the start of the column */
761 for (i
= MenuInfo
->iItem
;
762 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
770 MenuCleanupAllRosMenuItemInfo(MenuItems
);
771 return NO_SELECTED_ITEM
;
774 for (--i
; 0 != i
; --i
)
775 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
778 MenuCleanupAllRosMenuItemInfo(MenuItems
);
779 TRACE("ret %d.\n", i
);
784 /***********************************************************************
787 * Load the arrow bitmap. We can't do this from MenuInit since user32
788 * can also be used (and thus initialized) from text-mode.
791 MenuLoadBitmaps(VOID
)
793 /* Load system buttons bitmaps */
794 if (NULL
== BmpSysMenu
)
796 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
799 /////////// Make gpsi OBMI via callback //////////////
800 /***********************************************************************
803 HBITMAP
get_arrow_bitmap(void)
805 static HBITMAP arrow_bitmap
;
807 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
811 /***********************************************************************
812 * get_down_arrow_bitmap DFCS_MENUARROWDOWN
814 HBITMAP
get_down_arrow_bitmap(void)
816 static HBITMAP arrow_bitmap
;
818 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW
));
822 /***********************************************************************
823 * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
825 HBITMAP
get_down_arrow_inactive_bitmap(void)
827 static HBITMAP arrow_bitmap
;
829 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI
));
833 /***********************************************************************
834 * get_up_arrow_bitmap DFCS_MENUARROWUP
836 HBITMAP
get_up_arrow_bitmap(void)
838 static HBITMAP arrow_bitmap
;
840 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW
));
844 /***********************************************************************
845 * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
847 static HBITMAP
get_up_arrow_inactive_bitmap(void)
849 static HBITMAP arrow_bitmap
;
851 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI
));
855 /***********************************************************************
858 * Find a Sub menu. Return the position of the submenu, and modifies
859 * *hmenu in case it is found in another sub-menu.
860 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
862 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
864 PMENU menu
, pSubMenu
;
869 if (((*hmenu
)==(HMENU
)0xffff) ||(!(menu
= MENU_GetMenu(*hmenu
))))
870 return NO_SELECTED_ITEM
;
872 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
873 for (i
= 0; i
< menu
->cItems
; i
++, item
= item
->Next
? DesktopPtrToUser(item
->Next
) : NULL
)//item++)
875 if (!item
->spSubMenu
)
879 pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
880 hSubMenu
= UserHMGetHandle(pSubMenu
);
881 if (hSubMenu
== hSubTarget
)
887 HMENU hsubmenu
= hSubMenu
;
888 UINT pos
= MenuFindSubMenu( &hsubmenu
, hSubTarget
);
889 if (pos
!= NO_SELECTED_ITEM
)
897 return NO_SELECTED_ITEM
;
900 /***********************************************************************
901 * MENU_AdjustMenuItemRect
903 * Adjust menu item rectangle according to scrolling state.
906 MENU_AdjustMenuItemRect(PROSMENUINFO menu
, LPRECT rect
)
908 if (menu
->dwArrowsOn
)
910 UINT arrow_bitmap_height
;
913 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp
), &bmp
);
914 arrow_bitmap_height
= bmp
.bmHeight
;
915 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
916 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
920 /***********************************************************************
923 * Draws popup magic glyphs (can be found in system menu).
926 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
929 HFONT hFont
, hOldFont
;
935 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
938 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
941 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
944 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
948 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
951 ZeroMemory(&lf
, sizeof(LOGFONTW
));
952 InflateRect(r
, -2, -2);
953 lf
.lfHeight
= r
->bottom
- r
->top
;
955 lf
.lfWeight
= FW_NORMAL
;
956 lf
.lfCharSet
= DEFAULT_CHARSET
;
957 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
958 hFont
= CreateFontIndirect(&lf
);
959 /* save font and text color */
960 hOldFont
= SelectObject(dc
, hFont
);
961 clrsave
= GetTextColor(dc
);
962 bkmode
= GetBkMode(dc
);
963 /* set color and drawing mode */
964 SetBkMode(dc
, TRANSPARENT
);
970 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
971 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
974 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
975 /* draw selected symbol */
976 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
977 /* restore previous settings */
978 SetTextColor(dc
, clrsave
);
979 SelectObject(dc
, hOldFont
);
980 SetBkMode(dc
, bkmode
);
984 /***********************************************************************
987 * Find the menu item selected by a key press.
988 * Return item id, -1 if none, -2 if we should close the menu.
990 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
991 WCHAR Key
, BOOL ForceMenuChar
)
993 ROSMENUINFO SysMenuInfo
;
994 PROSMENUITEMINFO Items
, ItemInfo
;
999 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
1001 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
1003 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
1005 MenuInfo
= &SysMenuInfo
;
1013 if (NULL
!= MenuInfo
)
1015 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
1019 if ( !ForceMenuChar
)
1022 for (i
= 0; i
< MenuInfo
->cItems
; i
++, ItemInfo
++)
1024 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
1026 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
1029 p
= strchrW (p
+ 2, '&');
1031 while (p
!= NULL
&& p
[1] == '&');
1032 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
1037 Flags
|= MenuInfo
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
1038 Flags
|= MenuInfo
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0;
1040 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
1041 MAKEWPARAM(Key
, Flags
), (LPARAM
) MenuInfo
->Self
);
1042 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
1043 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
1048 /***********************************************************************
1049 * MenuGetBitmapItemSize
1051 * Get the size of a bitmap item.
1053 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
1056 HBITMAP bmp
= lpitem
->hbmpItem
;
1058 size
->cx
= size
->cy
= 0;
1060 /* check if there is a magic menu item associated with this item */
1061 if (IS_MAGIC_BITMAP(bmp
))
1063 switch((INT_PTR
) bmp
)
1065 case (INT_PTR
)HBMMENU_CALLBACK
:
1067 MEASUREITEMSTRUCT measItem
;
1068 measItem
.CtlType
= ODT_MENU
;
1070 measItem
.itemID
= lpitem
->wID
;
1071 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
1072 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
1073 measItem
.itemData
= lpitem
->dwItemData
;
1074 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
1075 size
->cx
= measItem
.itemWidth
;
1076 size
->cy
= measItem
.itemHeight
;
1081 case (INT_PTR
) HBMMENU_SYSTEM
:
1082 if (0 != lpitem
->dwItemData
)
1084 bmp
= (HBITMAP
) lpitem
->dwItemData
;
1088 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
1089 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
1090 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
1091 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
1092 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
1093 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1094 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1095 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1096 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1097 /* FIXME: Why we need to subtract these magic values? */
1098 /* to make them smaller than the menu bar? */
1099 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
1100 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
1105 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
1107 size
->cx
= bm
.bmWidth
;
1108 size
->cy
= bm
.bmHeight
;
1112 /***********************************************************************
1113 * MenuDrawBitmapItem
1115 * Draw a bitmap item.
1117 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
1118 PROSMENUINFO MenuInfo
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
1124 int w
= rect
->right
- rect
->left
;
1125 int h
= rect
->bottom
- rect
->top
;
1126 int bmp_xoffset
= 0;
1128 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
1131 /* Check if there is a magic menu item associated with this item */
1132 if (IS_MAGIC_BITMAP(hbmToDraw
))
1138 switch ((INT_PTR
)hbmToDraw
)
1140 case (INT_PTR
)HBMMENU_SYSTEM
:
1141 if (lpitem
->dwTypeData
)
1143 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
1144 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1148 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
1150 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
1151 /* only use right half of the bitmap */
1152 bmp_xoffset
= bm
.bmWidth
/ 2;
1153 bm
.bmWidth
-= bmp_xoffset
;
1156 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1157 flags
= DFCS_CAPTIONRESTORE
;
1159 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1161 flags
= DFCS_CAPTIONMIN
;
1163 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1165 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1167 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1168 flags
= DFCS_CAPTIONCLOSE
;
1170 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1171 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1173 case (INT_PTR
)HBMMENU_CALLBACK
:
1175 DRAWITEMSTRUCT drawItem
;
1177 drawItem
.CtlType
= ODT_MENU
;
1179 drawItem
.itemID
= lpitem
->wID
;
1180 drawItem
.itemAction
= odaction
;
1181 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1182 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1183 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1184 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1185 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1186 //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
1187 //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
1188 drawItem
.hwndItem
= (HWND
)MenuInfo
->Self
;
1190 drawItem
.rcItem
= *rect
;
1191 drawItem
.itemData
= lpitem
->dwItemData
;
1192 /* some applications make this assumption on the DC's origin */
1193 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
1194 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
1195 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1196 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1201 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1202 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1203 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1204 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1205 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1208 InflateRect(&r
, -1, -1);
1209 if (0 != (lpitem
->fState
& MF_HILITE
))
1211 flags
|= DFCS_PUSHED
;
1213 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1217 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1220 hdcMem
= CreateCompatibleDC( hdc
);
1221 SelectObject( hdcMem
, bmp
);
1223 /* handle fontsize > bitmap_height */
1224 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1226 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1227 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
1228 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1229 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
1233 /***********************************************************************
1236 * Calculate the size of the menu item and store it in lpitem->rect.
1238 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
1239 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1242 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1243 UINT arrow_bitmap_width
;
1247 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
1249 GetObjectW( get_arrow_bitmap(), sizeof(bm
), &bm
);
1250 arrow_bitmap_width
= bm
.bmWidth
;
1252 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
1254 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
1256 if (lpitem
->fType
& MF_OWNERDRAW
)
1258 MEASUREITEMSTRUCT mis
;
1259 mis
.CtlType
= ODT_MENU
;
1261 mis
.itemID
= lpitem
->wID
;
1262 mis
.itemData
= lpitem
->dwItemData
;
1263 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1265 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1266 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1267 * width of a menufont character to the width of an owner-drawn menu.
1269 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1271 /* under at least win95 you seem to be given a standard
1272 height for the menu and the height value is ignored */
1273 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1275 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
1277 //Item->cxBmp = mis.itemWidth;
1278 //Item->cyBmp = mis.itemHeight;
1279 TRACE("id=%04lx size=%dx%d\n",
1280 lpitem
->wID
, lpitem
->Rect
.right
-lpitem
->Rect
.left
,
1281 lpitem
->Rect
.bottom
-lpitem
->Rect
.top
);
1285 if (lpitem
->fType
& MF_SEPARATOR
)
1287 lpitem
->Rect
.bottom
+= GetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1289 lpitem
->Rect
.right
+= arrow_bitmap_width
/*check_bitmap_width*/ + MenuCharSize
.cx
;
1295 if (lpitem
->hbmpItem
)
1300 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1301 /* Keep the size of the bitmap in callback mode to be able
1302 * to draw it correctly */
1303 lpitem
->maxBmpSize
= size
;
1304 MenuInfo
->cxTextAlign
= max(MenuInfo
->cxTextAlign
, size
.cx
);
1305 MenuSetRosMenuInfo(MenuInfo
);
1306 lpitem
->Rect
.right
+= size
.cx
+ 2;
1307 itemheight
= size
.cy
+ 2;
1309 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1310 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
1311 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1312 lpitem
->dxTab
= lpitem
->Rect
.right
;
1313 lpitem
->Rect
.right
+= arrow_bitmap_width
;//check_bitmap_width;
1314 } else /* hbmpItem & MenuBar */ {
1315 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1316 lpitem
->Rect
.right
+= size
.cx
;
1317 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
1318 itemheight
= size
.cy
;
1320 /* Special case: Minimize button doesn't have a space behind it. */
1321 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1322 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1323 lpitem
->Rect
.right
-= 1;
1326 else if (!menuBar
) {
1327 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1328 lpitem
->Rect
.right
+= check_bitmap_width
;
1329 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1330 lpitem
->dxTab
= lpitem
->Rect
.right
;
1331 lpitem
->Rect
.right
+= check_bitmap_width
;
1334 /* it must be a text item - unless it's the system menu */
1335 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
1336 HFONT hfontOld
= NULL
;
1337 RECT rc
= lpitem
->Rect
;
1338 LONG txtheight
, txtwidth
;
1340 if ( lpitem
->fState
& MFS_DEFAULT
) {
1341 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1344 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
1345 DT_SINGLELINE
|DT_CALCRECT
);
1346 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
1347 itemheight
= max( max( itemheight
, txtheight
),
1348 GetSystemMetrics( SM_CYMENU
) - 1);
1349 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1351 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
1354 int n
= (int)( p
- lpitem
->dwTypeData
);
1355 /* Item contains a tab (only meaningful in popup menus) */
1356 /* get text size before the tab */
1357 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
1358 DT_SINGLELINE
|DT_CALCRECT
);
1359 txtwidth
= rc
.right
- rc
.left
;
1360 p
+= 1; /* advance past the Tab */
1361 /* get text size after the tab */
1362 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1363 DT_SINGLELINE
|DT_CALCRECT
);
1364 lpitem
->dxTab
+= txtwidth
;
1365 txtheight
= max( txtheight
, tmpheight
);
1366 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1367 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1369 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
1370 DT_SINGLELINE
|DT_CALCRECT
);
1371 txtwidth
= rc
.right
- rc
.left
;
1372 lpitem
->dxTab
+= txtwidth
;
1374 lpitem
->Rect
.right
+= 2 + txtwidth
;
1375 itemheight
= max( itemheight
,
1376 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1378 if (hfontOld
) SelectObject (hdc
, hfontOld
);
1379 } else if( menuBar
) {
1380 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1382 lpitem
->Rect
.bottom
+= itemheight
;
1383 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
1386 /***********************************************************************
1387 * MENU_GetMaxPopupHeight
1390 MENU_GetMaxPopupHeight(PROSMENUINFO lppop
)
1393 return lppop
->cyMax
;
1394 return GetSystemMetrics(SM_CYSCREEN
) - GetSystemMetrics(SM_CYBORDER
);
1397 /***********************************************************************
1398 * MenuPopupMenuCalcSize
1400 * Calculate the size of a popup menu.
1402 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1404 ROSMENUITEMINFO lpitem
;
1407 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1408 BOOL textandbmp
= FALSE
;
1410 MenuInfo
->cxMenu
= MenuInfo
->cyMenu
= 0;
1411 if (MenuInfo
->cItems
== 0)
1413 MenuSetRosMenuInfo(MenuInfo
);
1418 SelectObject( hdc
, hMenuFont
);
1423 MenuInfo
->cxTextAlign
= 0;
1425 MenuInitRosMenuItemInfo(&lpitem
);
1426 while (start
< MenuInfo
->cItems
)
1431 maxTab
= maxTabWidth
= 0;
1433 /* Parse items until column break or end of menu */
1434 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1436 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1438 MenuCleanupRosMenuItemInfo(&lpitem
);
1439 MenuSetRosMenuInfo(MenuInfo
);
1443 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1445 if( lpitem
.lpstr
&& lpitem
.hbmpItem
) textandbmp
= TRUE
;
1447 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
1448 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1450 MenuCleanupRosMenuItemInfo(&lpitem
);
1451 MenuSetRosMenuInfo(MenuInfo
);
1454 // Not sure here,, The patch from wine removes this.
1455 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
1459 maxX
= max(maxX
, lpitem
.Rect
.right
);
1460 orgY
= lpitem
.Rect
.bottom
;
1461 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
1463 maxTab
= max( maxTab
, lpitem
.dxTab
);
1464 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
1468 /* Finish the column (set all items to the largest width found) */
1469 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1472 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
1474 lpitem
.Rect
.right
= maxX
;
1475 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
1477 lpitem
.dxTab
= maxTab
;
1479 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
1483 MenuInfo
->cyMenu
= max(MenuInfo
->cyMenu
, orgY
);
1486 MenuInfo
->cxMenu
= maxX
;
1487 /* if none of the items have both text and bitmap then
1488 * the text and bitmaps are all aligned on the left. If there is at
1489 * least one item with both text and bitmap then bitmaps are
1490 * on the left and texts left aligned with the right hand side
1492 if( !textandbmp
) MenuInfo
->cxTextAlign
= 0;
1494 /* space for 3d border */
1495 MenuInfo
->cyMenu
+= MENU_BOTTOM_MARGIN
;
1496 MenuInfo
->cxMenu
+= 2;
1498 /* Adjust popup height if it exceeds maximum */
1499 maxHeight
= MENU_GetMaxPopupHeight(MenuInfo
);
1500 MenuInfo
->iMaxTop
= MenuInfo
->cyMenu
- MENU_TOP_MARGIN
;
1501 if (MenuInfo
->cyMenu
>= maxHeight
)
1503 MenuInfo
->cyMenu
= maxHeight
;
1504 MenuInfo
->dwArrowsOn
= 1;
1508 MenuInfo
->dwArrowsOn
= 0;
1511 MenuCleanupRosMenuItemInfo(&lpitem
);
1512 MenuSetRosMenuInfo(MenuInfo
);
1513 ReleaseDC( 0, hdc
);
1516 /***********************************************************************
1517 * MenuMenuBarCalcSize
1519 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1520 * height is off by 1 pixel which causes lengthy window relocations when
1521 * active document window is maximized/restored.
1523 * Calculate the size of the menu bar.
1525 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1526 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1528 ROSMENUITEMINFO ItemInfo
;
1529 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1531 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1532 if (MenuInfo
->cItems
== 0) return;
1533 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1534 MenuInfo
->cxMenu
= lprect
->right
- lprect
->left
;
1535 MenuInfo
->cyMenu
= 0;
1536 maxY
= lprect
->top
+ 1;
1540 MenuInfo
->cxTextAlign
= 0;
1542 MenuInitRosMenuItemInfo(&ItemInfo
);
1543 while (start
< MenuInfo
->cItems
)
1545 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1547 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1550 orgX
= lprect
->left
;
1553 /* Parse items until line break or end of menu */
1554 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1556 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1558 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1560 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1561 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
1562 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1564 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1568 if (ItemInfo
.Rect
.right
> lprect
->right
)
1570 if (i
!= start
) break;
1571 else ItemInfo
.Rect
.right
= lprect
->right
;
1573 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1574 orgX
= ItemInfo
.Rect
.right
;
1575 if (i
+ 1 < MenuInfo
->cItems
)
1577 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1579 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1585 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1586 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1588 /* Finish the line (set all items to the largest height found) */
1591 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1593 ItemInfo
.Rect
.bottom
= maxY
;
1594 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1599 start
= i
; /* This works! */
1603 lprect
->bottom
= maxY
;
1604 MenuInfo
->cyMenu
= lprect
->bottom
- lprect
->top
;
1605 MenuSetRosMenuInfo(MenuInfo
);
1609 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1610 /* the last item (if several lines, only move the last line) */
1611 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->cItems
- 1, &ItemInfo
))
1613 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1616 orgY
= ItemInfo
.Rect
.top
;
1617 orgX
= lprect
->right
;
1618 for (i
= MenuInfo
->cItems
- 1; helpPos
<= i
; i
--)
1624 if (ItemInfo
.Rect
.top
!= orgY
)
1626 break; /* Other line */
1628 if (orgX
<= ItemInfo
.Rect
.right
)
1630 break; /* Too far right already */
1632 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1633 ItemInfo
.Rect
.right
= orgX
;
1634 orgX
= ItemInfo
.Rect
.left
;
1635 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1636 if (helpPos
+ 1 <= i
&&
1637 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1639 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1645 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1648 /***********************************************************************
1649 * MENU_DrawScrollArrows
1651 * Draw scroll arrows.
1654 MENU_DrawScrollArrows(PROSMENUINFO lppop
, HDC hdc
)
1656 HDC hdcMem
= CreateCompatibleDC(hdc
);
1657 HBITMAP hOrigBitmap
;
1658 UINT arrow_bitmap_width
, arrow_bitmap_height
;
1662 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
1663 arrow_bitmap_width
= bmp
.bmWidth
;
1664 arrow_bitmap_height
= bmp
.bmHeight
;
1668 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_bitmap());
1670 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_inactive_bitmap());
1673 rect
.right
= lppop
->cxMenu
;
1674 rect
.bottom
= arrow_bitmap_height
;
1675 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1676 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2, 0,
1677 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1678 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
1679 rect
.bottom
= lppop
->cyMenu
;
1680 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1681 if (lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
))
1682 SelectObject(hdcMem
, get_down_arrow_bitmap());
1684 SelectObject(hdcMem
, get_down_arrow_inactive_bitmap());
1685 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2,
1686 lppop
->cyMenu
- arrow_bitmap_height
,
1687 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1688 SelectObject(hdcMem
, hOrigBitmap
);
1693 /***********************************************************************
1696 * Draw a single menu item.
1698 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1699 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1703 BOOL flat_menu
= FALSE
;
1705 PWND Wnd
= ValidateHwnd(hWnd
);
1710 if (lpitem
->fType
& MF_SYSMENU
)
1712 if ( (Wnd
->style
& WS_MINIMIZE
))
1714 UserGetInsideRectNC(Wnd
, &rect
);
1715 UserDrawSysMenuButton(hWnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1720 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1721 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1725 if (lpitem
->fState
& MF_HILITE
)
1727 if(menuBar
&& !flat_menu
) {
1728 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1729 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1731 if (lpitem
->fState
& MF_GRAYED
)
1732 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1734 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1735 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1740 if (lpitem
->fState
& MF_GRAYED
)
1741 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1743 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1744 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1747 rect
= lpitem
->Rect
;
1748 MENU_AdjustMenuItemRect(MenuInfo
, &rect
);
1750 if (lpitem
->fType
& MF_OWNERDRAW
)
1753 ** Experimentation under Windows reveals that an owner-drawn
1754 ** menu is given the rectangle which includes the space it requested
1755 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1756 ** and a popup-menu arrow. This is the value of lpitem->rect.
1757 ** Windows will leave all drawing to the application except for
1758 ** the popup-menu arrow. Windows always draws that itself, after
1759 ** the menu owner has finished drawing.
1763 dis
.CtlType
= ODT_MENU
;
1765 dis
.itemID
= lpitem
->wID
;
1766 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1768 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1769 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
1770 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
1771 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1772 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1773 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1774 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1775 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1776 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1779 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1780 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1781 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1782 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1784 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1785 /* Draw the popup-menu arrow */
1786 if (lpitem
->hSubMenu
)
1789 CopyRect(&rectTemp
, &rect
);
1790 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1791 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1796 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1798 if (lpitem
->fState
& MF_HILITE
)
1802 InflateRect (&rect
, -1, -1);
1803 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1804 InflateRect (&rect
, 1, 1);
1805 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1810 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1812 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1816 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1818 SetBkMode( hdc
, TRANSPARENT
);
1820 /* vertical separator */
1821 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1828 rc
.bottom
= Height
- 3;
1831 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1832 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1833 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1834 LineTo( hdc
, rc
.left
, rc
.bottom
);
1835 SelectObject( hdc
, oldPen
);
1838 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1841 /* horizontal separator */
1842 if (lpitem
->fType
& MF_SEPARATOR
)
1849 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1852 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1853 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1854 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1855 LineTo( hdc
, rc
.right
, rc
.top
);
1856 SelectObject( hdc
, oldPen
);
1859 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1864 /* helper lines for debugging */
1865 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1866 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1867 SelectObject(hdc
, GetStockObject(DC_PEN
));
1868 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1869 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1870 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1876 INT y
= rect
.top
+ rect
.bottom
;
1878 BOOL checked
= FALSE
;
1879 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1880 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1881 /* Draw the check mark
1884 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1886 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1887 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1888 lpitem
->hbmpUnchecked
;
1889 if (bm
) /* we have a custom bitmap */
1891 HDC hdcMem
= CreateCompatibleDC( hdc
);
1893 SelectObject( hdcMem
, bm
);
1894 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1895 check_bitmap_width
, check_bitmap_height
,
1896 hdcMem
, 0, 0, SRCCOPY
);
1900 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1903 CopyRect(&r
, &rect
);
1904 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1905 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1906 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1907 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1911 if ( lpitem
->hbmpItem
)
1914 CopyRect(&bmpRect
, &rect
);
1915 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1916 bmpRect
.left
+= check_bitmap_width
+ 2;
1917 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1919 bmpRect
.right
= bmpRect
.left
+ lpitem
->maxBmpSize
.cx
;
1920 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1923 /* Draw the popup-menu arrow */
1924 if (lpitem
->hSubMenu
)
1927 CopyRect(&rectTemp
, &rect
);
1928 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1929 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1932 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1933 rect
.left
+= check_bitmap_width
;
1934 rect
.right
-= check_bitmap_width
;
1936 else if( lpitem
->hbmpItem
)
1937 { /* Draw the bitmap */
1938 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1941 /* process text if present */
1947 UINT uFormat
= menuBar
?
1948 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1949 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1951 if((MenuInfo
->dwStyle
& MNS_CHECKORBMP
))
1952 rect
.left
+= max(0, MenuInfo
->cxTextAlign
- GetSystemMetrics(SM_CXMENUCHECK
));
1954 rect
.left
+= MenuInfo
->cxTextAlign
;
1956 if ( lpitem
->fState
& MFS_DEFAULT
)
1958 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1962 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1963 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1966 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1969 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1970 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1974 if(lpitem
->fState
& MF_GRAYED
)
1976 if (!(lpitem
->fState
& MF_HILITE
) )
1978 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1979 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1980 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1981 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1983 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1986 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1988 /* paint the shortcut text */
1989 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1991 if (L
'\t' == Text
[i
])
1993 rect
.left
= lpitem
->dxTab
;
1994 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1998 rect
.right
= lpitem
->dxTab
;
1999 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
2002 if (lpitem
->fState
& MF_GRAYED
)
2004 if (!(lpitem
->fState
& MF_HILITE
) )
2006 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
2007 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
2008 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2009 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
2011 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
2013 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
2017 SelectObject (hdc
, hfontOld
);
2021 /***********************************************************************
2024 * Paint a popup menu.
2026 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
2028 HBRUSH hPrevBrush
= 0;
2031 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
2033 GetClientRect( hwnd
, &rect
);
2035 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
2036 && (SelectObject( hdc
, hMenuFont
)))
2040 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2042 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
2045 BOOL flat_menu
= FALSE
;
2046 ROSMENUINFO MenuInfo
;
2047 ROSMENUITEMINFO ItemInfo
;
2049 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2051 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
2053 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
2055 /* draw menu items */
2056 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.cItems
)
2059 MenuInitRosMenuItemInfo(&ItemInfo
);
2061 for (u
= 0; u
< MenuInfo
.cItems
; u
++)
2063 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
2065 HWND WndOwner
= MenuInfo
.spwndNotify
? MenuInfo
.spwndNotify
->head
.h
: NULL
;
2066 MenuDrawMenuItem(hwnd
, &MenuInfo
, WndOwner
, hdc
, &ItemInfo
,
2067 MenuInfo
.cyMenu
, FALSE
, ODA_DRAWENTIRE
);
2071 /* draw scroll arrows */
2072 if (MenuInfo
.dwArrowsOn
)
2073 MENU_DrawScrollArrows(&MenuInfo
, hdc
);
2075 MenuSetRosMenuInfo(&MenuInfo
);
2076 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2080 SelectObject( hdc
, hPrevBrush
);
2085 /***********************************************************************
2088 * Paint a menu bar. Returns the height of the menu bar.
2089 * called from [windows/nonclient.c]
2091 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
2096 HMENU hMenu
= GetMenu(hwnd
);
2098 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
2100 return GetSystemMetrics(SM_CYMENU
);
2105 hfontOld
= SelectObject(hDC
, hMenuFont
);
2107 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
2109 lprect
->bottom
= lprect
->top
+ lppop
.cyMenu
;
2111 if (hfontOld
) SelectObject( hDC
, hfontOld
);
2112 return lppop
.cyMenu
;
2115 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
2119 /***********************************************************************
2122 * Display a popup menu.
2124 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
2125 INT x
, INT y
, INT xanchor
, INT yanchor
)
2127 ROSMENUINFO MenuInfo
;
2128 ROSMENUITEMINFO ItemInfo
;
2135 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2136 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
2138 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
2139 if (MenuInfo
.iItem
!= NO_SELECTED_ITEM
)
2141 MenuInitRosMenuItemInfo(&ItemInfo
);
2142 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
))
2144 ItemInfo
.fMask
|= MIIM_STATE
;
2145 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2146 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
);
2148 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2149 MenuInfo
.iItem
= NO_SELECTED_ITEM
;
2152 /* store the owner for DrawItem */
2153 if (!IsWindow(hwndOwner
))
2155 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2158 MenuInfo
.spwndNotify
= ValidateHwndNoErr(hwndOwner
);
2159 MenuSetRosMenuInfo(&MenuInfo
);
2161 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
2163 /* adjust popup menu pos so that it fits within the desktop */
2165 width
= MenuInfo
.cxMenu
+ GetSystemMetrics(SM_CXBORDER
);
2166 height
= MenuInfo
.cyMenu
+ GetSystemMetrics(SM_CYBORDER
);
2168 /* FIXME: should use item rect */
2171 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2172 info
.cbSize
= sizeof(info
);
2173 GetMonitorInfoW( monitor
, &info
);
2175 if (flags
& TPM_LAYOUTRTL
)
2177 ex_style
= WS_EX_LAYOUTRTL
;
2178 flags
^= TPM_RIGHTALIGN
;
2180 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2181 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2183 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2184 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2186 if( x
+ width
> info
.rcMonitor
.right
)
2188 if( xanchor
&& x
>= width
- xanchor
)
2189 x
-= width
- xanchor
;
2191 if( x
+ width
> info
.rcMonitor
.right
)
2192 x
= info
.rcMonitor
.right
- width
;
2194 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
2196 if( y
+ height
> info
.rcMonitor
.bottom
)
2198 if( yanchor
&& y
>= height
+ yanchor
)
2199 y
-= height
+ yanchor
;
2201 if( y
+ height
> info
.rcMonitor
.bottom
)
2202 y
= info
.rcMonitor
.bottom
- height
;
2204 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
2206 /* NOTE: In Windows, top menu popup is not owned. */
2207 MenuInfo
.Wnd
= CreateWindowExW( ex_style
, WC_MENU
, NULL
,
2208 WS_POPUP
, x
, y
, width
, height
,
2209 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
2210 (LPVOID
) MenuInfo
.Self
);
2211 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
2213 top_popup
= MenuInfo
.Wnd
;
2214 top_popup_hmenu
= hmenu
;
2217 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2219 /* Display the window */
2221 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
2222 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2223 UpdateWindow( MenuInfo
.Wnd
);
2227 /***********************************************************************
2228 * MENU_EnsureMenuItemVisible
2231 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop
, PROSMENUITEMINFO item
, HDC hdc
)
2233 if (lppop
->dwArrowsOn
)
2235 //ITEM *item = &lppop->items[wIndex];
2236 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2237 UINT nOldPos
= lppop
->iTop
;
2239 UINT arrow_bitmap_height
;
2242 GetClientRect(lppop
->Wnd
, &rc
);
2244 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
2245 arrow_bitmap_height
= bmp
.bmHeight
;
2247 rc
.top
+= arrow_bitmap_height
;
2248 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2250 nMaxHeight
-= GetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2251 if (item
->Rect
.bottom
> lppop
->iTop
+ nMaxHeight
)
2253 lppop
->iTop
= item
->Rect
.bottom
- nMaxHeight
;
2254 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2255 MENU_DrawScrollArrows(lppop
, hdc
);
2257 else if (item
->Rect
.top
- MENU_TOP_MARGIN
< lppop
->iTop
)
2259 lppop
->iTop
= item
->Rect
.top
- MENU_TOP_MARGIN
;
2260 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2261 MENU_DrawScrollArrows(lppop
, hdc
);
2266 /***********************************************************************
2269 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
2270 BOOL sendMenuSelect
, HMENU topmenu
)
2272 ROSMENUITEMINFO ItemInfo
;
2273 ROSMENUINFO TopMenuInfo
;
2276 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
2278 if (!hmenu
|| !hmenu
->cItems
|| !hmenu
->Wnd
) return;
2279 if (hmenu
->iItem
== wIndex
) return;
2280 if (hmenu
->fFlags
& MNF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
2281 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2283 top_popup
= hmenu
->Wnd
;
2284 top_popup_hmenu
= hmenu
->Self
;
2287 SelectObject( hdc
, hMenuFont
);
2289 MenuInitRosMenuItemInfo(&ItemInfo
);
2291 /* Clear previous highlighted item */
2292 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2294 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2296 ItemInfo
.fMask
|= MIIM_STATE
;
2297 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2298 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2300 //MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
2301 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
2302 hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2306 /* Highlight new item (if any) */
2307 hmenu
->iItem
= wIndex
;
2308 MenuSetRosMenuInfo(hmenu
);
2309 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2311 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2313 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
2315 ItemInfo
.fMask
|= MIIM_STATE
;
2316 ItemInfo
.fState
|= MF_HILITE
;
2317 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2318 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
2319 &ItemInfo
, hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2324 WPARAM wParam
= MAKEWPARAM( ItemInfo
.hSubMenu
? wIndex
: ItemInfo
.wID
,
2325 ItemInfo
.fType
| ItemInfo
.fState
|
2326 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2327 (hmenu
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2329 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) hmenu
->Self
);
2333 else if (sendMenuSelect
)
2338 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
2339 if (pos
!= NO_SELECTED_ITEM
)
2341 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
2342 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
2344 WPARAM wParam
= MAKEWPARAM( Pos
, ItemInfo
.fType
| ItemInfo
.fState
|
2345 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2346 (TopMenuInfo
.fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2348 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) topmenu
);
2353 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2354 ReleaseDC(hmenu
->Wnd
, hdc
);
2357 /***********************************************************************
2360 * Moves currently selected item according to the Offset parameter.
2361 * If there is no selection then it should select the last item if
2362 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2364 static void FASTCALL
2365 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2368 ROSMENUITEMINFO ItemInfo
;
2371 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2373 /* Prevent looping */
2374 if (0 == MenuInfo
->cItems
|| 0 == Offset
)
2376 else if (Offset
< -1)
2378 else if (Offset
> 1)
2381 MenuInitRosMenuItemInfo(&ItemInfo
);
2383 OrigPos
= MenuInfo
->iItem
;
2384 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2391 i
= MenuInfo
->iItem
;
2398 /* Clip and wrap around */
2401 i
= MenuInfo
->cItems
- 1;
2403 else if (i
>= MenuInfo
->cItems
)
2407 /* If this is a good candidate; */
2408 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2409 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2411 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2412 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2415 } while (i
!= OrigPos
);
2418 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2423 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2425 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2427 PPOPUPMENU pPopupMenu
;
2429 pWnd
= ValidateHwnd(Wnd
);
2434 if (Message
!= WM_NCCREATE
)
2436 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2438 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2439 pPopupMenu
= HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU
) );
2440 pPopupMenu
->spwndPopupMenu
= pWnd
;
2441 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)pPopupMenu
);
2445 if (pWnd
->fnid
!= FNID_MENU
)
2447 ERR("Wrong window class for Menu!\n");
2450 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
2455 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2461 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2462 pPopupMenu
->spmenu
= ValidateHandle(cs
->lpCreateParams
, TYPE_MENU
);
2466 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2467 return MA_NOACTIVATE
;
2472 BeginPaint(Wnd
, &ps
);
2473 MenuDrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
->head
.h
);
2478 case WM_PRINTCLIENT
:
2480 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
->head
.h
);
2488 /* zero out global pointer in case resident popup window was destroyed. */
2489 if (Wnd
== top_popup
)
2492 top_popup_hmenu
= NULL
;
2498 HeapFree( GetProcessHeap(), 0, pPopupMenu
);
2499 SetWindowLongPtrW(Wnd
, 0, 0);
2500 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2507 if (!pPopupMenu
|| !pPopupMenu
->spmenu
)
2509 OutputDebugStringA("no menu to display\n");
2514 pPopupMenu->spmenu = NULL; ///// WTF?
2518 case MM_SETMENUHANDLE
:
2520 PMENU pmenu
= ValidateHandle((HMENU
)wParam
, TYPE_MENU
);
2523 ERR("Bad Menu Handle\n");
2526 pPopupMenu
->spmenu
= pmenu
;
2530 case MM_GETMENUHANDLE
:
2532 return (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? pPopupMenu
->spmenu
->head
.h
: NULL
) : NULL
);
2535 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2543 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2545 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2548 pWnd
= ValidateHwnd(Wnd
);
2553 if (Message
!= WM_NCCREATE
)
2555 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2557 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2561 if (pWnd
->fnid
!= FNID_MENU
)
2563 ERR("Wrong window class for Menu!\n");
2570 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2576 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2577 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
2581 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2582 return MA_NOACTIVATE
;
2587 BeginPaint(Wnd
, &ps
);
2588 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
2593 case WM_PRINTCLIENT
:
2595 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
2596 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
2604 /* zero out global pointer in case resident popup window was destroyed. */
2605 if (Wnd
== top_popup
)
2608 top_popup_hmenu
= NULL
;
2615 if (0 == GetWindowLongPtrW(Wnd
, 0))
2617 OutputDebugStringA("no menu to display\n");
2622 SetWindowLongPtrW(Wnd
, 0, 0);
2626 case MM_SETMENUHANDLE
:
2627 SetWindowLongPtrW(Wnd
, 0, wParam
);
2630 case MM_GETMENUHANDLE
:
2632 return GetWindowLongPtrW(Wnd
, 0);
2635 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2642 // This breaks some test results. Should handle A2U if called!
2644 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2648 pWnd
= ValidateHwnd(Wnd
);
2649 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
2651 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2653 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2659 case WM_MOUSEACTIVATE
:
2661 case WM_PRINTCLIENT
:
2666 case MM_SETMENUHANDLE
:
2667 case MM_GETMENUHANDLE
:
2669 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
2672 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2677 /**********************************************************************
2678 * MENU_ParseResource
2680 * Parse a standard menu resource and add items to the menu.
2681 * Return a pointer to the end of the resource.
2683 * NOTE: flags is equivalent to the mtOption field
2685 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2694 flags
= GET_WORD(res
);
2696 /* remove MF_END flag before passing it to AppendMenu()! */
2697 end
= (flags
& MF_END
);
2698 if(end
) flags
^= MF_END
;
2700 res
+= sizeof(WORD
);
2701 if(!(flags
& MF_POPUP
))
2704 res
+= sizeof(WORD
);
2707 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2709 if (flags
& MF_POPUP
)
2711 hSubMenu
= CreatePopupMenu();
2712 if(!hSubMenu
) return NULL
;
2713 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
2714 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
2716 else /* Not a popup */
2718 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2725 /**********************************************************************
2726 * MENUEX_ParseResource
2728 * Parse an extended menu resource and add items to the menu.
2729 * Return a pointer to the end of the resource.
2731 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2738 mii
.cbSize
= sizeof(mii
);
2739 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2740 mii
.fType
= GET_DWORD(res
);
2741 res
+= sizeof(DWORD
);
2742 mii
.fState
= GET_DWORD(res
);
2743 res
+= sizeof(DWORD
);
2744 mii
.wID
= GET_DWORD(res
);
2745 res
+= sizeof(DWORD
);
2746 resinfo
= GET_WORD(res
);
2747 res
+= sizeof(WORD
);
2748 /* Align the text on a word boundary. */
2749 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2750 mii
.dwTypeData
= (LPWSTR
)res
;
2751 mii
.cch
= strlenW(mii
.dwTypeData
);
2752 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2753 /* Align the following fields on a dword boundary. */
2754 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2756 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2757 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2759 if (resinfo
& 1) /* Pop-up? */
2761 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2762 res
+= sizeof(DWORD
);
2763 mii
.hSubMenu
= CreatePopupMenu();
2766 ERR("CreatePopupMenu failed\n");
2770 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2772 ERR("MENUEX_ParseResource failed\n");
2773 DestroyMenu(mii
.hSubMenu
);
2776 mii
.fMask
|= MIIM_SUBMENU
;
2778 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
2780 mii
.fType
|= MF_SEPARATOR
;
2782 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2783 } while (!(resinfo
& MF_END
));
2788 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2790 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2791 LRESULT Result
= (LRESULT
)hmenu
;
2792 MENUINFO menuinfo
= {0};
2793 MENUITEMINFOW info
= {0};
2795 // removing space for checkboxes from menu
2796 menuinfo
.cbSize
= sizeof(menuinfo
);
2797 menuinfo
.fMask
= MIM_STYLE
;
2798 GetMenuInfo(hmenu
, &menuinfo
);
2799 menuinfo
.dwStyle
|= MNS_CHECKORBMP
; // test_menu_bmp_and_string MNS_CHECKORBMP
2800 SetMenuInfo(hmenu
, &menuinfo
);
2802 // adding bitmaps to menu items
2803 info
.cbSize
= sizeof(info
);
2804 info
.fMask
|= MIIM_BITMAP
;
2805 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2806 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2807 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2808 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2809 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2810 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2811 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2812 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2814 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2821 NONCLIENTMETRICSW ncm
;
2823 /* get the menu font */
2824 if(!hMenuFont
|| !hMenuFontBold
)
2826 ncm
.cbSize
= sizeof(ncm
);
2827 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2829 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2833 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2834 if(hMenuFont
== NULL
)
2836 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2840 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2841 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2842 if(hMenuFontBold
== NULL
)
2844 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2845 DeleteObject(hMenuFont
);
2859 DeleteObject(hMenuFont
);
2865 DeleteObject(hMenuFontBold
);
2866 hMenuFontBold
= NULL
;
2870 /***********************************************************************
2871 * DrawMenuBarTemp (USER32.@)
2875 * called by W98SE desk.cpl Control Panel Applet
2877 * Not 100% sure about the param names, but close.
2882 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2884 ROSMENUINFO MenuInfo
;
2885 ROSMENUITEMINFO ItemInfo
;
2887 HFONT FontOld
= NULL
;
2888 BOOL flat_menu
= FALSE
;
2890 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2894 Menu
= GetMenu(Wnd
);
2902 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2904 return GetSystemMetrics(SM_CYMENU
);
2907 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2909 FontOld
= SelectObject(DC
, Font
);
2911 if (0 == MenuInfo
.cyMenu
)
2913 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2916 Rect
->bottom
= Rect
->top
+ MenuInfo
.cyMenu
;
2918 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2920 SelectObject(DC
, GetStockObject(DC_PEN
));
2921 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2922 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2923 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2925 if (0 == MenuInfo
.cItems
)
2927 SelectObject(DC
, FontOld
);
2928 return GetSystemMetrics(SM_CYMENU
);
2931 MenuInitRosMenuItemInfo(&ItemInfo
);
2932 for (i
= 0; i
< MenuInfo
.cItems
; i
++)
2934 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2936 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2937 MenuInfo
.cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2940 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2942 SelectObject(DC
, FontOld
);
2944 return MenuInfo
.cyMenu
;
2947 static BOOL
MENU_InitPopup( HWND hwndOwner
, HMENU hmenu
, UINT flags
)
2952 TRACE("owner=%p hmenu=%p\n", hwndOwner
, hmenu
);
2954 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2956 /* store the owner for DrawItem */
2957 if (!IsWindow( hwndOwner
))
2959 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2962 menu
->hwndOwner
= hwndOwner
;
2964 if (flags
& TPM_LAYOUTRTL
)
2965 ex_style
= WS_EX_LAYOUTRTL
;
2967 /* NOTE: In Windows, top menu popup is not owned. */
2968 menu
->hWnd
= CreateWindowExW( ex_style
, (LPCWSTR
)POPUPMENU_CLASS_ATOM
, NULL
,
2969 WS_POPUP
, 0, 0, 0, 0,
2970 hwndOwner
, 0, (HINSTANCE
)GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
2972 if( !menu
->hWnd
) return FALSE
;
2976 /***********************************************************************
2979 * Display the sub-menu of the selected item of this menu.
2980 * Return the handle of the submenu, or menu if no submenu to display.
2982 static HMENU FASTCALL
2983 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2985 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2987 ROSMENUITEMINFO ItemInfo
;
2988 ROSMENUINFO SubMenuInfo
;
2992 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2994 if (NO_SELECTED_ITEM
== MenuInfo
->iItem
)
2996 return MenuInfo
->Self
;
2999 MenuInitRosMenuItemInfo(&ItemInfo
);
3000 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3002 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3003 return MenuInfo
->Self
;
3005 if (0 == (ItemInfo
.hSubMenu
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
3007 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3008 return MenuInfo
->Self
;
3011 /* message must be sent before using item,
3012 because nearly everything may be changed by the application ! */
3014 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3015 if (0 == (Flags
& TPM_NONOTIFY
))
3017 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
3018 MAKELPARAM(MenuInfo
->iItem
, IS_SYSTEM_MENU(MenuInfo
)));
3021 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3023 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3024 return MenuInfo
->Self
;
3026 Rect
= ItemInfo
.Rect
;
3028 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3029 if (0 == (ItemInfo
.fState
& MF_HILITE
))
3031 if (0 != (MenuInfo
->fFlags
& MNF_POPUP
))
3033 Dc
= GetDC(MenuInfo
->Wnd
);
3037 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3040 SelectObject(Dc
, hMenuFont
);
3041 ItemInfo
.fMask
|= MIIM_STATE
;
3042 ItemInfo
.fState
|= MF_HILITE
;
3043 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
3044 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->cyMenu
,
3045 !(MenuInfo
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
3046 ReleaseDC(MenuInfo
->Wnd
, Dc
);
3049 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
3050 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
3052 ItemInfo
.Rect
= Rect
;
3055 ItemInfo
.fMask
|= MIIM_STATE
;
3056 ItemInfo
.fState
|= MF_MOUSESELECT
;
3057 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
3059 if (IS_SYSTEM_MENU(MenuInfo
))
3061 ERR("Right click on window bar and Draw system menu!\n");
3062 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
3063 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
3064 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
;
3065 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
3066 Rect
.top
= Rect
.bottom
;
3067 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
3068 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
3072 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
3073 if (0 != (MenuInfo
->fFlags
& MNF_POPUP
))
3075 RECT rc
= ItemInfo
.Rect
;
3077 MENU_AdjustMenuItemRect(MenuInfo
, &rc
);
3079 if(Flags
& TPM_LAYOUTRTL
)
3080 Rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
3082 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
3083 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
3084 Rect
.right
= rc
.left
- rc
.right
+ GetSystemMetrics(SM_CXBORDER
);
3085 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
3086 - GetSystemMetrics(SM_CYBORDER
);
3090 if(Flags
& TPM_LAYOUTRTL
)
3091 Rect
.left
+= Rect
.right
- ItemInfo
.Rect
.left
;
3093 Rect
.left
+= ItemInfo
.Rect
.left
;
3094 Rect
.top
+= ItemInfo
.Rect
.bottom
;
3095 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
3096 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
3100 /* use default alignment for submenus */
3101 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
3103 //MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags );
3105 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->iItem
, Flags
,
3106 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
3107 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
3109 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
3112 Ret
= ItemInfo
.hSubMenu
;
3113 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3118 /**********************************************************************
3121 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
3123 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
3125 void MENU_EndMenu( HWND hwnd
)
3127 ROSMENUINFO MenuInfo
;
3129 if (top_popup_hmenu
)
3130 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
3131 if (Ret
&& hwnd
== (MenuInfo
.spwndNotify
? MenuInfo
.spwndNotify
->head
.h
: NULL
)) EndMenu();
3134 /***********************************************************************
3137 * Hide the sub-popup menus of this menu.
3139 static void FASTCALL
3140 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
3141 BOOL SendMenuSelect
, UINT wFlags
)
3143 ROSMENUINFO SubMenuInfo
;
3144 ROSMENUITEMINFO ItemInfo
;
3146 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
3148 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->iItem
)
3150 MenuInitRosMenuItemInfo(&ItemInfo
);
3151 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
3152 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
)
3153 || 0 == (ItemInfo
.hSubMenu
)
3154 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
3156 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3159 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
3160 ItemInfo
.fMask
|= MIIM_STATE
;
3161 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
3162 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
3164 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
3165 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
3166 DestroyWindow(SubMenuInfo
.Wnd
);
3167 SubMenuInfo
.Wnd
= NULL
;
3168 MenuSetRosMenuInfo(&SubMenuInfo
);
3170 if (!(wFlags
& TPM_NONOTIFY
))
3171 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
3172 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
3177 /***********************************************************************
3178 * MenuSwitchTracking
3180 * Helper function for menu navigation routines.
3182 static void FASTCALL
3183 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
3185 ROSMENUINFO TopMenuInfo
;
3187 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
3189 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
3190 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
3191 0 == ((PtMenuInfo
->fFlags
| TopMenuInfo
.fFlags
) & MNF_POPUP
))
3193 /* both are top level menus (system and menu-bar) */
3194 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3195 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3196 Mt
->TopMenu
= PtMenuInfo
->Self
;
3200 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
3203 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
3206 /***********************************************************************
3207 * MenuExecFocusedItem
3209 * Execute a menu item (for instance when user pressed Enter).
3210 * Return the wID of the executed item. Otherwise, -1 indicating
3211 * that no menu item was executed, -2 if a popup is shown;
3212 * Have to receive the flags for the TrackPopupMenu options to avoid
3213 * sending unwanted message.
3217 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
3219 ROSMENUITEMINFO ItemInfo
;
3222 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
3224 if (0 == MenuInfo
->cItems
|| NO_SELECTED_ITEM
== MenuInfo
->iItem
)
3229 MenuInitRosMenuItemInfo(&ItemInfo
);
3230 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3232 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3236 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
3238 if (0 == (ItemInfo
.hSubMenu
))
3240 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
3241 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
3243 /* If TPM_RETURNCMD is set you return the id, but
3244 do not send a message to the owner */
3245 if (0 == (Flags
& TPM_RETURNCMD
))
3247 if (0 != (MenuInfo
->fFlags
& MNF_SYSDESKMN
))
3249 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
3250 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
3254 ROSMENUINFO topmenuI
;
3255 BOOL ret
= MenuGetRosMenuInfo(&topmenuI
, Mt
->TopMenu
);
3256 DWORD dwStyle
= MenuInfo
->dwStyle
| (ret
? topmenuI
.dwStyle
: 0);
3258 if (dwStyle
& MNS_NOTIFYBYPOS
)
3259 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
, MenuInfo
->iItem
, (LPARAM
)MenuInfo
->Self
);
3261 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
3265 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3271 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
3278 /***********************************************************************
3281 * Return TRUE if we can go on with menu tracking.
3283 static BOOL FASTCALL
3284 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
3287 ROSMENUINFO MenuInfo
;
3288 ROSMENUITEMINFO Item
;
3290 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
3294 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3298 if (IS_SYSTEM_MENU(&MenuInfo
))
3304 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3306 MenuInitRosMenuItemInfo(&Item
);
3307 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
3309 MenuCleanupRosMenuItemInfo(&Item
);
3313 if (!(Item
.fType
& MF_SEPARATOR
) &&
3314 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
3316 if (MenuInfo
.iItem
!= Index
)
3318 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3321 /* If the popup menu is not already "popped" */
3322 if (0 == (Item
.fState
& MF_MOUSESELECT
))
3324 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3328 MenuCleanupRosMenuItemInfo(&Item
);
3333 /* else the click was on the menu bar, finish the tracking */
3338 /***********************************************************************
3341 * Return the value of MenuExecFocusedItem if
3342 * the selected item was not a popup. Else open the popup.
3343 * A -1 return value indicates that we go on with menu tracking.
3347 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3350 ROSMENUINFO MenuInfo
;
3351 ROSMENUITEMINFO ItemInfo
;
3353 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
3358 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3363 if (! IS_SYSTEM_MENU(&MenuInfo
))
3365 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3367 MenuInitRosMenuItemInfo(&ItemInfo
);
3368 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
3369 MenuInfo
.iItem
== Id
)
3371 if (0 == (ItemInfo
.hSubMenu
))
3373 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
3374 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3375 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
3377 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3379 /* If we are dealing with the top-level menu */
3380 /* and this is a click on an already "popped" item: */
3381 /* Stop the menu tracking and close the opened submenus */
3382 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
3384 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3388 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3389 MenuInfo
.TimeToHide
= TRUE
;
3390 MenuSetRosMenuInfo(&MenuInfo
);
3396 /***********************************************************************
3399 * Walks menu chain trying to find a menu pt maps to.
3401 static HMENU FASTCALL
3402 MenuPtMenu(HMENU Menu
, POINT Pt
)
3404 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
3405 ROSMENUINFO MenuInfo
;
3406 ROSMENUITEMINFO ItemInfo
;
3410 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3415 /* try subpopup first (if any) */
3416 if (NO_SELECTED_ITEM
!= MenuInfo
.iItem
)
3418 MenuInitRosMenuItemInfo(&ItemInfo
);
3419 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
) &&
3420 0 != (ItemInfo
.hSubMenu
) &&
3421 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
3423 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
3426 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3430 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3433 /* check the current window (avoiding WM_HITTEST) */
3434 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
3435 if (0 != (MenuInfo
.fFlags
& MNF_POPUP
))
3437 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
3442 else if (HTSYSMENU
== Ht
)
3444 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
3446 else if (HTMENU
== Ht
)
3448 Ret
= GetMenu(MenuInfo
.Wnd
);
3454 /***********************************************************************
3457 * Return TRUE if we can go on with menu tracking.
3459 static BOOL FASTCALL
3460 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3463 ROSMENUINFO MenuInfo
;
3464 ROSMENUITEMINFO ItemInfo
;
3468 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3472 if (IS_SYSTEM_MENU(&MenuInfo
))
3478 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3483 Index
= NO_SELECTED_ITEM
;
3486 if (NO_SELECTED_ITEM
== Index
)
3488 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
3489 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3491 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3495 else if (MenuInfo
.iItem
!= Index
)
3497 MenuInitRosMenuItemInfo(&ItemInfo
);
3498 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
3499 !(ItemInfo
.fType
& MF_SEPARATOR
))
3501 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3502 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
3503 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3505 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3511 /***********************************************************************
3514 * Return the handle of the selected sub-popup menu (if any).
3516 static HMENU FASTCALL
3517 MenuGetSubPopup(HMENU Menu
)
3519 ROSMENUINFO MenuInfo
;
3520 ROSMENUITEMINFO ItemInfo
;
3522 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
3523 || NO_SELECTED_ITEM
== MenuInfo
.iItem
)
3528 MenuInitRosMenuItemInfo(&ItemInfo
);
3529 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
))
3531 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3534 if (0 != (ItemInfo
.hSubMenu
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
3536 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3537 return ItemInfo
.hSubMenu
;
3540 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3544 /***********************************************************************
3547 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3549 static LRESULT FASTCALL
3550 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
3552 ROSMENUINFO TopMenuInfo
;
3553 ROSMENUINFO MenuInfo
;
3555 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3557 return (LRESULT
) FALSE
;
3560 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.iItem
)
3561 || (VK_RIGHT
== Vk
&& TopMenuInfo
.iItem
== TopMenuInfo
.cItems
- 1))
3563 MDINEXTMENU NextMenu
;
3568 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
3569 NextMenu
.hmenuNext
= NULL
;
3570 NextMenu
.hwndNext
= NULL
;
3571 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3573 TRACE("%p [%p] -> %p [%p]\n",
3574 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3576 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3578 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
3579 NewWnd
= Mt
->OwnerWnd
;
3580 if (IS_SYSTEM_MENU(&TopMenuInfo
))
3582 /* switch to the menu bar */
3584 if (0 != (Style
& WS_CHILD
)
3585 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
3592 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
3596 Id
= MenuInfo
.cItems
- 1;
3599 else if (0 != (Style
& WS_SYSMENU
))
3601 /* switch to the system menu */
3602 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
3609 else /* application returned a new menu to switch to */
3611 NewMenu
= NextMenu
.hmenuNext
;
3612 NewWnd
= NextMenu
.hwndNext
;
3614 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
3616 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
3618 if (0 != (Style
& WS_SYSMENU
)
3619 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
3621 /* get the real system menu */
3622 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
3624 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
3626 /* FIXME: Not sure what to do here;
3627 * perhaps try to track NewMenu as a popup? */
3629 WARN(" -- got confused.\n");
3639 if (NewMenu
!= Mt
->TopMenu
)
3641 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3643 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3645 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3649 if (NewWnd
!= Mt
->OwnerWnd
)
3651 Mt
->OwnerWnd
= NewWnd
;
3652 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
3653 SetCapture(Mt
->OwnerWnd
); // 2
3656 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3657 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3659 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3668 /***********************************************************************
3671 * The idea is not to show the popup if the next input message is
3672 * going to hide it anyway.
3674 static BOOL FASTCALL
3675 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
3679 msg
.hwnd
= Mt
->OwnerWnd
;
3681 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
3682 // Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
3687 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3688 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3690 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3691 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3692 if( msg
.message
== WM_KEYDOWN
&&
3693 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3695 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3701 /* failures go through this */
3702 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3706 /***********************************************************************
3709 * Handle a VK_ESCAPE key event in a menu.
3711 static BOOL FASTCALL
3712 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3714 BOOL EndMenu
= TRUE
;
3715 ROSMENUINFO MenuInfo
;
3716 HMENU MenuTmp
, MenuPrev
;
3718 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3720 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3721 && 0 != (MenuInfo
.fFlags
& MNF_POPUP
))
3723 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3725 /* close topmost popup */
3726 while (MenuTmp
!= Mt
->CurrentMenu
)
3729 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3732 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3734 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3736 Mt
->CurrentMenu
= MenuPrev
;
3744 /***********************************************************************
3747 * Handle a VK_LEFT key event in a menu.
3749 static void FASTCALL
3750 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3752 ROSMENUINFO MenuInfo
;
3753 ROSMENUINFO TopMenuInfo
;
3754 ROSMENUINFO PrevMenuInfo
;
3755 HMENU MenuTmp
, MenuPrev
;
3758 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3760 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3765 /* Try to move 1 column left (if possible) */
3766 if ( (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)) != NO_SELECTED_ITEM
)
3768 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3770 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3775 /* close topmost popup */
3776 while (MenuTmp
!= Mt
->CurrentMenu
)
3779 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3782 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3786 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3787 Mt
->CurrentMenu
= MenuPrev
;
3789 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3793 if ((MenuPrev
== Mt
->TopMenu
) && !(TopMenuInfo
.fFlags
& MNF_POPUP
))
3795 /* move menu bar selection if no more popups are left */
3797 if (!MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3799 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3802 if (MenuPrev
!= MenuTmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3804 /* A sublevel menu was displayed - display the next one
3805 * unless there is another displacement coming up */
3807 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3808 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3810 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3817 /***********************************************************************
3820 * Handle a VK_RIGHT key event in a menu.
3822 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3825 ROSMENUINFO MenuInfo
;
3826 ROSMENUINFO CurrentMenuInfo
;
3829 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3830 Mt
->CurrentMenu
, Mt
->TopMenu
);
3832 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3833 if ((MenuInfo
.fFlags
& MNF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3835 /* If already displaying a popup, try to display sub-popup */
3837 hmenutmp
= Mt
->CurrentMenu
;
3838 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3840 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3843 /* if subpopup was displayed then we are done */
3844 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3847 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3852 /* Check to see if there's another column */
3853 if ( (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)) != NO_SELECTED_ITEM
)
3855 TRACE("Going to %d.\n", NextCol
);
3856 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3858 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3863 if (!(MenuInfo
.fFlags
& MNF_POPUP
)) /* menu bar tracking */
3865 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3867 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3868 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3875 /* try to move to the next item */
3876 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3877 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3879 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3881 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3882 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3884 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3891 /***********************************************************************
3894 * Menu tracking code.
3896 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3897 HWND hwnd
, const RECT
*lprect
)
3900 ROSMENUINFO MenuInfo
;
3901 ROSMENUITEMINFO ItemInfo
;
3903 INT executedMenuId
= -1;
3906 BOOL enterIdleSent
= FALSE
;
3909 mt
.CurrentMenu
= hmenu
;
3915 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3916 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3917 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3921 WARN("Invalid menu handle %p\n", hmenu
);
3922 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3927 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3932 if (wFlags
& TPM_BUTTONDOWN
)
3934 /* Get the result in order to start the tracking or not */
3935 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3936 fEndMenu
= !fRemove
;
3939 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3941 /* owner may not be visible when tracking a popup, so use the menu itself */
3942 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3943 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3944 SetCapture(capture_win
); // 2
3948 BOOL ErrorExit
= FALSE
;
3949 PMENU menu
= ValidateHandle(mt
.CurrentMenu
, TYPE_MENU
);
3950 if (!menu
) /* sometimes happens if I do a window manager close */
3953 /* we have to keep the message in the queue until it's
3954 * clear that menu loop is not over yet. */
3958 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3960 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3961 /* remove the message from the queue */
3962 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3967 if (!ValidateHwnd(mt
.OwnerWnd
) || !ValidateHwnd(MenuInfo
.Wnd
))
3969 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3974 HWND win
= MenuInfo
.fFlags
& MNF_POPUP
? MenuInfo
.Wnd
: NULL
;
3975 enterIdleSent
= TRUE
;
3976 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3982 if (ErrorExit
) break; // Gracefully dropout.
3984 /* check if EndMenu() tried to cancel us, by posting this message */
3985 if (msg
.message
== WM_CANCELMODE
)
3987 /* we are now out of the loop */
3990 /* remove the message from the queue */
3991 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3993 /* break out of internal loop, ala ESCAPE */
3997 TranslateMessage( &msg
);
4000 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
4001 enterIdleSent
=FALSE
;
4004 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
4007 * Use the mouse coordinates in lParam instead of those in the MSG
4008 * struct to properly handle synthetic messages. They are already
4009 * in screen coordinates.
4011 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
4012 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
4014 /* Find a menu for this mouse event */
4015 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
4019 /* no WM_NC... messages in captured state */
4021 case WM_RBUTTONDBLCLK
:
4022 ERR("WM_RBUTTONDBLCLK\n");
4023 case WM_RBUTTONDOWN
:
4024 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
4026 case WM_LBUTTONDBLCLK
:
4027 case WM_LBUTTONDOWN
:
4028 /* If the message belongs to the menu, removes it from the queue */
4029 /* Else, end menu tracking */
4030 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
4031 fEndMenu
= !fRemove
;
4035 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
4038 /* Check if a menu was selected by the mouse */
4041 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
4042 TRACE("executedMenuId %d\n", executedMenuId
);
4044 /* End the loop if executedMenuId is an item ID */
4045 /* or if the job was done (executedMenuId = 0). */
4046 fEndMenu
= fRemove
= (executedMenuId
!= -1);
4048 /* No menu was selected by the mouse */
4049 /* if the function was called by TrackPopupMenu, continue
4050 with the menu tracking. If not, stop it */
4052 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
4057 /* the selected menu item must be changed every time */
4058 /* the mouse moves. */
4061 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
4063 } /* switch(msg.message) - mouse */
4065 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
4067 fRemove
= TRUE
; /* Keyboard messages are always removed */
4081 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
4083 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
4084 NO_SELECTED_ITEM
, FALSE
, 0 );
4085 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
4086 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
4091 case VK_DOWN
: /* If on menu bar, pull-down the menu */
4092 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
4094 if (!(MenuInfo
.fFlags
& MNF_POPUP
))
4096 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4097 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
4099 else /* otherwise try to move selection */
4100 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
4101 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
4106 MenuKeyLeft( &mt
, wFlags
);
4110 MenuKeyRight( &mt
, wFlags
);
4114 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
4120 hi
.cbSize
= sizeof(HELPINFO
);
4121 hi
.iContextType
= HELPINFO_MENUITEM
;
4122 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
4124 if (MenuInfo
.iItem
== NO_SELECTED_ITEM
)
4128 MenuInitRosMenuItemInfo(&ItemInfo
);
4129 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
4133 hi
.iCtrlId
= ItemInfo
.wID
;
4139 MenuCleanupRosMenuItemInfo(&ItemInfo
);
4142 hi
.hItemHandle
= hmenu
;
4143 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
4144 hi
.MousePos
= msg
.pt
;
4145 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
4152 break; /* WM_KEYDOWN */
4159 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
4160 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
4162 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
4163 fEndMenu
= (executedMenuId
!= -2);
4167 /* Hack to avoid control chars. */
4168 /* We will find a better way real soon... */
4169 if (msg
.wParam
< 32) break;
4171 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
4172 LOWORD(msg
.wParam
), FALSE
);
4173 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
4174 else if (pos
== (UINT
)-1) MessageBeep(0);
4177 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
4179 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
4180 fEndMenu
= (executedMenuId
!= -2);
4184 } /* switch(msg.message) - kbd */
4188 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
4189 DispatchMessageW( &msg
);
4193 if (!fEndMenu
) fRemove
= TRUE
;
4195 /* finally remove message from the queue */
4197 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
4198 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
4199 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4202 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
4203 SetCapture(NULL
); /* release the capture */
4205 /* If dropdown is still painted and the close box is clicked on
4206 then the menu will be destroyed as part of the DispatchMessage above.
4207 This will then invalidate the menu handle in mt.hTopMenu. We should
4208 check for this first. */
4209 if( IsMenu( mt
.TopMenu
) )
4211 if (IsWindow(mt
.OwnerWnd
))
4213 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4215 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
4217 if (MenuInfo
.fFlags
& MNF_POPUP
)
4219 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4220 DestroyWindow(MenuInfo
.Wnd
);
4221 MenuInfo
.Wnd
= NULL
;
4223 if (!(wFlags
& TPM_NONOTIFY
))
4224 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
4225 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
4227 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
4230 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4233 /* Reset the variable for hiding menu */
4234 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4236 MenuInfo
.TimeToHide
= FALSE
;
4237 MenuSetRosMenuInfo(&MenuInfo
);
4241 /* The return value is only used by TrackPopupMenu */
4242 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4243 if (executedMenuId
== -1) executedMenuId
= 0;
4244 return executedMenuId
;
4247 /***********************************************************************
4250 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
4252 ROSMENUINFO MenuInfo
;
4254 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
4258 /* This makes the menus of applications built with Delphi work.
4259 * It also enables menus to be displayed in more than one window,
4260 * but there are some bugs left that need to be fixed in this case.
4262 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
4264 MenuInfo
.Wnd
= hWnd
;
4265 MenuSetRosMenuInfo(&MenuInfo
);
4268 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4269 if (!(wFlags
& TPM_NONOTIFY
))
4270 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
4272 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
4274 if (!(wFlags
& TPM_NONOTIFY
))
4276 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
4277 /* If an app changed/recreated menu bar entries in WM_INITMENU
4278 * menu sizes will be recalculated once the menu created/shown.
4281 if (!MenuInfo
.cyMenu
)
4283 /* app changed/recreated menu bar entries in WM_INITMENU
4284 Recalculate menu sizes else clicks will not work */
4285 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4286 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4291 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4293 MenuInfo
.fFlags
& MNF_SYSDESKMN
? OBJID_SYSMENU
: OBJID_MENU
,
4297 /***********************************************************************
4300 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
4302 TRACE("hwnd=%p\n", hWnd
);
4304 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4305 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
4308 top_popup_hmenu
= NULL
;
4312 /***********************************************************************
4313 * MenuTrackMouseMenuBar
4315 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4317 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
4319 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
4320 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4322 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
4324 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4327 /* map point to parent client coordinates */
4328 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
4329 if (Parent
!= GetDesktopWindow())
4331 ScreenToClient(Parent
, &pt
);
4334 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
4335 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
4336 MenuExitTracking(hWnd
, FALSE
);
4341 /***********************************************************************
4342 * MenuTrackKbdMenuBar
4344 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4346 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
4348 UINT uItem
= NO_SELECTED_ITEM
;
4350 ROSMENUINFO MenuInfo
;
4351 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4353 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
4355 /* find window that has a menu */
4357 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
4358 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
4359 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
4361 /* check if we have to track a system menu */
4363 hTrackMenu
= GetMenu( hwnd
);
4364 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
4366 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
4367 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
4369 wParam
|= HTSYSMENU
; /* prevent item lookup */
4372 if (!IsMenu( hTrackMenu
)) return;
4374 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
4376 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
4381 if( wChar
&& wChar
!= ' ' )
4383 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
4384 if ( uItem
>= (UINT
)(-2) )
4386 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
4387 /* schedule end of menu tracking */
4388 wFlags
|= TF_ENDMENU
;
4393 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
4395 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4397 if( uItem
== NO_SELECTED_ITEM
)
4398 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
4400 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
4404 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
4405 MenuExitTracking( hwnd
, FALSE
);
4408 /**********************************************************************
4409 * TrackPopupMenuEx (USER32.@)
4411 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
4412 HWND Wnd
, LPTPMPARAMS Tpm
)
4415 ROSMENUINFO MenuInfo
;
4419 SetLastError( ERROR_INVALID_MENU_HANDLE
);
4424 if (!ValidateHwnd(Wnd
))
4426 /* invalid window see wine menu.c test_menu_trackpopupmenu line 3146 */
4430 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4431 if (IsWindow(MenuInfo
.Wnd
))
4433 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4437 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
4439 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4440 if (!(Flags
& TPM_NONOTIFY
))
4441 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
4443 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
4444 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
4445 Tpm
? &Tpm
->rcExclude
: NULL
);
4446 MenuExitTracking(Wnd
, TRUE
);
4450 /**********************************************************************
4451 * TrackPopupMenu (USER32.@)
4453 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
4454 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
4456 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
4461 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
4462 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
4464 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
4466 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
4467 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
4468 * MFT_STRING is replaced by MIIM_STRING.
4469 * (So, I guess we should use MIIM_STRING only for strings?)
4471 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
4473 * Based on wine, SetMenuItemInfo_common:
4474 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
4475 * it will result in a error.
4476 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
4477 * These conditions are addressed in Win32k IntSetMenuItemInfo.
4484 LPMENUITEMINFOW mii
,
4491 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
4493 if(Flags
& MF_BITMAP
)
4495 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
4496 mii
->hbmpItem
= (HBITMAP
) NewItem
;
4498 if (Flags
& MF_HELP
)
4500 /* increase ident */
4501 mii
->fType
|= MF_HELP
;
4504 else if(Flags
& MF_OWNERDRAW
)
4506 mii
->fType
|= MFT_OWNERDRAW
;
4507 mii
->fMask
|= MIIM_DATA
;
4508 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
4510 else if (Flags
& MF_SEPARATOR
)
4512 mii
->fType
|= MFT_SEPARATOR
;
4513 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
4514 Flags
|= MF_GRAYED
|MF_DISABLED
;
4516 else /* Default action MF_STRING. */
4518 /* Item beginning with a backspace is a help item */
4519 if (NewItem
!= NULL
)
4523 if (*NewItem
== '\b')
4525 mii
->fType
|= MF_HELP
;
4531 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
4532 if (*NewItemA
== '\b')
4534 mii
->fType
|= MF_HELP
;
4536 NewItem
= (LPCWSTR
) NewItemA
;
4540 if (Flags
& MF_HELP
)
4541 mii
->fType
|= MF_HELP
;
4542 mii
->fMask
|= MIIM_STRING
;
4543 mii
->fType
|= MFT_STRING
; /* Zero */
4544 mii
->dwTypeData
= (LPWSTR
)NewItem
;
4546 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
4548 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
4552 mii
->fType
|= MFT_SEPARATOR
;
4553 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
4554 Flags
|= MF_GRAYED
|MF_DISABLED
;
4558 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
4560 mii
->fType
|= MFT_RIGHTJUSTIFY
;
4563 if(Flags
& MF_MENUBREAK
)
4565 mii
->fType
|= MFT_MENUBREAK
;
4567 else if(Flags
& MF_MENUBARBREAK
)
4569 mii
->fType
|= MFT_MENUBARBREAK
;
4572 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
4574 if (Flags
& MF_GRAYED
)
4575 mii
->fState
|= MF_GRAYED
;
4577 if (Flags
& MF_DISABLED
)
4578 mii
->fState
|= MF_DISABLED
;
4580 mii
->fMask
|= MIIM_STATE
;
4582 else if (Flags
& MF_HILITE
)
4584 mii
->fState
|= MF_HILITE
;
4585 mii
->fMask
|= MIIM_STATE
;
4587 else /* default state */
4589 mii
->fState
|= MFS_ENABLED
;
4590 mii
->fMask
|= MIIM_STATE
;
4593 if(Flags
& MF_POPUP
&& IsMenu((HMENU
)IDNewItem
))
4595 mii
->fMask
|= MIIM_SUBMENU
;
4596 mii
->hSubMenu
= (HMENU
)IDNewItem
;
4598 mii
->fMask
|= MIIM_ID
;
4599 mii
->wID
= (UINT
)IDNewItem
;
4604 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
4606 PLOADMENU_CALLBACK_ARGUMENTS Common
;
4609 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
4611 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
4612 IS_INTRESOURCE(Common
->MenuName
[0]) ?
4613 MAKEINTRESOURCE(Common
->MenuName
[0]) :
4614 (LPCWSTR
)&Common
->MenuName
);
4616 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
4619 /**********************************************************************
4620 * MENU_NormalizeMenuItemInfoStruct
4622 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
4623 * check, copy and extend the MENUITEMINFO struct from the version that the application
4624 * supplied to the version used by wine source. */
4625 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
4626 MENUITEMINFOW
*pmii_out
)
4628 /* do we recognize the size? */
4629 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
4630 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
4631 SetLastError( ERROR_INVALID_PARAMETER
);
4634 /* copy the fields that we have */
4635 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
4636 /* if the hbmpItem member is missing then extend */
4637 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
4638 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
4639 pmii_out
->hbmpItem
= NULL
;
4641 /* test for invalid bit combinations */
4642 if( (pmii_out
->fMask
& MIIM_TYPE
&&
4643 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
4644 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
4645 ERR("invalid combination of fMask bits used\n");
4646 /* this does not happen on Win9x/ME */
4647 SetLastError( ERROR_INVALID_PARAMETER
);
4650 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
4651 if( pmii_out
->fMask
& MIIM_TYPE
){
4652 pmii_out
->fMask
|= MIIM_FTYPE
;
4653 if( IS_STRING_ITEM(pmii_out
->fType
)){
4654 pmii_out
->fMask
|= MIIM_STRING
;
4655 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
4656 pmii_out
->fMask
|= MIIM_BITMAP
;
4657 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
4660 if (pmii_out
->fMask
& MIIM_FTYPE
)
4662 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
4663 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
4665 if (pmii_out
->fMask
& MIIM_STATE
)
4666 /* Other menu items having MFS_DEFAULT are not converted
4668 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
4674 /* FUNCTIONS *****************************************************************/
4680 AppendMenuA(HMENU hMenu
,
4682 UINT_PTR uIDNewItem
,
4685 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
, lpNewItem
));
4692 AppendMenuW(HMENU hMenu
,
4694 UINT_PTR uIDNewItem
,
4697 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
, lpNewItem
));
4704 CheckMenuItem(HMENU hmenu
,
4712 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4715 if (!(item
= MENU_FindItem( &hmenu
, &uIDCheckItem
, uCheck
))) return -1;
4717 Ret
= item
->fState
& MFS_CHECKED
;
4718 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
4720 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4728 CheckMenuRadioItem(HMENU hMenu
,
4736 PITEM mi_first
= NULL
, mi_check
;
4737 HMENU m_first
, m_check
;
4739 mii
.cbSize
= sizeof( mii
);
4741 for (i
= first
; i
<= last
; i
++)
4748 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
4749 if (!mi_first
) continue;
4750 mi_check
= mi_first
;
4756 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
4757 if (!mi_check
) continue;
4760 if (m_first
!= m_check
) continue;
4761 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
4765 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
4767 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
4768 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
4769 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
4770 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4776 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
4777 if (mi_check
->fState
& MFS_CHECKED
)
4779 mii
.fMask
= MIIM_STATE
;
4780 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
4781 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4795 return NtUserxCreateMenu();
4802 CreatePopupMenu(VOID
)
4805 return NtUserxCreatePopupMenu();
4812 DrawMenuBar(HWND hWnd
)
4814 return NtUserxDrawMenuBar(hWnd
);
4821 EnableMenuItem(HMENU hMenu
,
4825 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4835 guii
.cbSize
= sizeof(GUITHREADINFO
);
4836 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4840 guii
.hwndMenuOwner
!= top_popup
)
4842 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4846 /* if we are in the menu code, and it is active */
4847 if (!fEndMenu
&& top_popup
)
4849 /* terminate the menu handling code */
4852 /* needs to be posted to wakeup the internal menu handler */
4853 /* which will now terminate the menu, in the event that */
4854 /* the main window was minimized, or lost focus, so we */
4855 /* don't end up with an orphaned menu */
4856 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4861 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4864 ROSMENUINFO MenuInfo
;
4865 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4866 // Force bits to be set call server side....
4867 // This alone works and passes all the menu test_menu_hilitemenuitem tests.
4868 if (!NtUserHiliteMenuItem(hWnd
, hMenu
, wItemID
, wHilite
)) return FALSE
;
4869 // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
4871 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
4873 if (MenuInfo
.iItem
== wItemID
) return TRUE
;
4874 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4875 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4877 return TRUE
; // Always returns TRUE!
4886 PWND Wnd
= ValidateHwnd(hWnd
);
4891 return UlongToHandle(Wnd
->IDMenu
);
4898 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4901 Ret
= NtUserGetMenuBarInfo( hwnd
, idObject
, idItem
, pmbi
);
4902 // Reason to move to server side!!!!!
4903 if (!Ret
) return Ret
;
4905 pmbi
->fBarFocused
= top_popup_hmenu
== pmbi
->hMenu
;
4908 pmbi
->fFocused
= pmbi
->fBarFocused
;
4918 GetMenuCheckMarkDimensions(VOID
)
4920 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4921 GetSystemMetrics(SM_CYMENUCHECK
)));
4929 GetMenuContextHelpId(HMENU hmenu
)
4932 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4933 return pMenu
->dwContextHelpId
;
4941 GetMenuDefaultItem(HMENU hMenu
,
4947 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
4950 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
4957 GetMenuInfo(HMENU hmenu
,
4962 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4964 SetLastError(ERROR_INVALID_PARAMETER
);
4968 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4971 if (lpcmi
->fMask
& MIM_BACKGROUND
)
4972 lpcmi
->hbrBack
= pMenu
->hbrBack
;
4974 if (lpcmi
->fMask
& MIM_HELPID
)
4975 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
4977 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
4978 lpcmi
->cyMax
= pMenu
->cyMax
;
4980 if (lpcmi
->fMask
& MIM_MENUDATA
)
4981 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
4983 if (lpcmi
->fMask
& MIM_STYLE
)
4984 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
4993 GetMenuItemCount(HMENU hmenu
)
4996 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4997 return pMenu
->cItems
;
5005 GetMenuItemID(HMENU hMenu
,
5012 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
5015 pItem
= pMenu
->rgItems
? DesktopPtrToUser(pMenu
->rgItems
) : NULL
;
5018 //pItem = &menu->rgItems[nPos]; or pItem[nPos]; after dptu.
5019 while(pItem
) // Do this for now.
5021 if (i
< (INT
)pMenu
->cItems
)
5023 if ( nPos
== i
&& !pItem
->spSubMenu
) return pItem
->wID
;
5025 pItem
= pItem
->Next
? DesktopPtrToUser(pItem
->Next
) : NULL
;
5040 LPMENUITEMINFOA lpmii
)
5045 if( lpmii
->cbSize
!= sizeof( mii
) &&
5046 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
5048 SetLastError( ERROR_INVALID_PARAMETER
);
5051 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
5052 mii
.cbSize
= sizeof( mii
);
5053 ret
= GetMenuItemInfo_common (hmenu
,
5056 (LPMENUITEMINFOW
)&mii
,
5058 mii
.cbSize
= lpmii
->cbSize
;
5059 memcpy( lpmii
, &mii
, mii
.cbSize
);
5071 LPMENUITEMINFOW lpmii
)
5075 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
5077 SetLastError( ERROR_INVALID_PARAMETER
);
5080 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
5081 mii
.cbSize
= sizeof( mii
);
5082 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
5083 mii
.cbSize
= lpmii
->cbSize
;
5084 memcpy( lpmii
, &mii
, mii
.cbSize
);
5099 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
5100 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
5102 if (pItem
->spSubMenu
)
5104 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
5105 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
5106 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
5107 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
) & 0xff);
5110 return (pItem
->fType
| pItem
->fState
);
5125 /* MENUITEMINFOA mii;
5126 memset( &mii, 0, sizeof(mii) );
5127 mii.dwTypeData = lpString;
5128 mii.fMask = MIIM_STRING;
5129 mii.cbSize = sizeof(MENUITEMINFOA);
5130 mii.cch = nMaxCount;
5132 if(!(GetMenuItemInfoA( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&mii)))
5139 ////// wine Code, seems to be faster.
5140 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
5142 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
5144 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
5146 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
5150 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
5152 if (!text
) return 0;
5153 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
5154 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
5155 lpString
[nMaxCount
-1] = 0;
5156 ERR("returning %s\n", lpString
);
5157 return strlen(lpString
);
5172 /* MENUITEMINFOW miiW;
5173 memset( &miiW, 0, sizeof(miiW) );
5174 miiW.dwTypeData = lpString;
5175 miiW.fMask = MIIM_STRING | MIIM_FTYPE;
5176 miiW.fType = MFT_STRING;
5177 miiW.cbSize = sizeof(MENUITEMINFOW);
5178 miiW.cch = nMaxCount;
5180 if(!(GetMenuItemInfoW( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&miiW)))
5188 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
5190 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
5192 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
5194 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
5198 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
5200 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
5206 lstrcpynW( lpString
, text
, nMaxCount
);
5207 ERR("returning %S\n", lpString
);
5208 return strlenW(lpString
);
5221 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
5223 if (pItem
->spSubMenu
)
5225 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
5226 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
5227 if (IsMenu(hsubmenu
)) return hsubmenu
;
5243 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
5245 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
5257 UINT_PTR uIDNewItem
,
5261 memset( &mii
, 0, sizeof(mii
) );
5262 mii
.cbSize
= sizeof(MENUITEMINFOA
);
5263 mii
.fMask
= MIIM_FTYPE
;
5265 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
5268 (LPCWSTR
) lpNewItem
,
5271 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
5283 LPCMENUITEMINFOA lpmii
)
5286 UNICODE_STRING UnicodeString
;
5289 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5291 RtlInitUnicodeString(&UnicodeString
, 0);
5293 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5295 /* copy the text string */
5296 if (((mii
.fMask
& MIIM_STRING
) ||
5297 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5298 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5300 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5302 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5305 mii
.dwTypeData
= UnicodeString
.Buffer
;
5306 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5310 UnicodeString
.Buffer
= NULL
;
5312 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
5313 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5326 LPCMENUITEMINFOW lpmii
)
5329 UNICODE_STRING MenuText
;
5332 /* while we could just pass 'lpmii' to win32k, we make a copy so that
5333 if a bad user passes bad data, we crash his process instead of the
5336 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5338 RtlInitUnicodeString(&MenuText
, 0);
5340 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5342 /* copy the text string */
5343 if (((mii
.fMask
& MIIM_STRING
) ||
5344 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5345 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5347 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
5348 mii
.dwTypeData
= MenuText
.Buffer
;
5349 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5351 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
5364 UINT_PTR uIDNewItem
,
5368 memset( &mii
, 0, sizeof(mii
) );
5369 mii
.cbSize
= sizeof(MENUITEMINFOW
);
5370 mii
.fMask
= MIIM_FTYPE
;
5372 MenuSetItemData( &mii
,
5378 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
5389 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
5397 LoadMenuA(HINSTANCE hInstance
,
5400 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
5401 if (Resource
== NULL
)
5405 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
5412 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
5414 return(LoadMenuIndirectW(lpMenuTemplate
));
5421 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
5424 WORD version
, offset
;
5425 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
5427 version
= GET_WORD(p
);
5432 case 0: /* standard format is version of 0 */
5433 offset
= GET_WORD(p
);
5434 p
+= sizeof(WORD
) + offset
;
5435 if (!(hMenu
= CreateMenu())) return 0;
5436 if (!MENU_ParseResource(p
, hMenu
))
5442 case 1: /* extended format is version of 1 */
5443 offset
= GET_WORD(p
);
5444 p
+= sizeof(WORD
) + offset
;
5445 if (!(hMenu
= CreateMenu())) return 0;
5446 if (!MENUEX_ParseResource(p
, hMenu
))
5448 DestroyMenu( hMenu
);
5453 ERR("Menu template version %d not supported.\n", version
);
5462 LoadMenuW(HINSTANCE hInstance
,
5465 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
5466 if (Resource
== NULL
)
5470 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
5483 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
5495 UINT_PTR uIDNewItem
,
5499 memset( &mii
, 0, sizeof(mii
) );
5500 mii
.cbSize
= sizeof(MENUITEMINFOA
);
5501 mii
.fMask
= MIIM_FTYPE
;
5503 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
5506 (LPCWSTR
) lpNewItem
,
5509 //if (mii.hSubMenu && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
5510 // NtUserDestroyMenu( mii.hSubMenu ); /* ModifyMenu() spec */
5512 return SetMenuItemInfoA( hMnu
,
5514 (BOOL
)(MF_BYPOSITION
& uFlags
),
5527 UINT_PTR uIDNewItem
,
5531 memset ( &mii
, 0, sizeof(mii
) );
5532 mii
.cbSize
= sizeof(MENUITEMINFOW
);
5533 mii
.fMask
= MIIM_FTYPE
;
5535 /* Init new data for this menu item */
5536 MenuSetItemData( &mii
,
5542 //if (mii.hSubMenu && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
5543 // NtUserDestroyMenu( mii.hSubMenu ); /* ModifyMenu() spec */
5545 return SetMenuItemInfoW( hMnu
,
5547 (BOOL
)(MF_BYPOSITION
& uFlags
),
5558 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
5573 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
5575 SetLastError(ERROR_INVALID_PARAMETER
);
5579 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5580 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
5592 HBITMAP hBitmapUnchecked
,
5593 HBITMAP hBitmapChecked
)
5595 MENUITEMINFOW uItem
;
5596 memset ( &uItem
, 0, sizeof(uItem
) );
5597 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
5598 uItem
.fMask
= MIIM_CHECKMARKS
;
5599 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5600 uItem
.hbmpChecked
= hBitmapChecked
;
5601 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
5613 LPCMENUITEMINFOA lpmii
)
5616 UNICODE_STRING UnicodeString
;
5619 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
5621 RtlInitUnicodeString(&UnicodeString
, 0);
5623 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5625 * MIIM_STRING == good
5626 * MIIM_TYPE & MFT_STRING == good
5627 * MIIM_STRING & MFT_STRING == good
5628 * MIIM_STRING & MFT_OWNERDRAW == good
5630 if (((mii
.fMask
& MIIM_STRING
) ||
5631 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5632 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5634 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5635 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5637 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5640 mii
.dwTypeData
= UnicodeString
.Buffer
;
5641 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5645 UnicodeString
.Buffer
= NULL
;
5647 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
5648 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
5661 LPCMENUITEMINFOW lpmii
)
5663 MENUITEMINFOW MenuItemInfoW
;
5664 UNICODE_STRING UnicodeString
;
5667 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5669 RtlInitUnicodeString(&UnicodeString
, 0);
5671 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
5673 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5674 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5675 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5676 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
5678 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
5679 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5681 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
5697 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5702 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5705 return NtUserSetSystemMenu(hwnd
, hMenu
);
5709 // Example for the Win32/User32 rewrite.
5710 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5724 return NtUserTrackPopupMenuEx( Menu
,
5729 NULL
); // LPTPMPARAMS is null
5750 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5753 Result
= (ULONG_PTR
)lResult
;
5758 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5778 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5781 Result
= (ULONG_PTR
)lResult
;
5786 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5797 LPCWSTR lpszNewItem
,
5802 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5803 for MF_DELETE. We should check the parameters for all others
5804 MF_* actions also (anybody got a doc on ChangeMenu?).
5807 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5810 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5813 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5816 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5819 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5820 flags
&~ MF_REMOVE
);
5822 default : /* MF_INSERT */
5823 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5840 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5841 for MF_DELETE. We should check the parameters for all others
5842 MF_* actions also (anybody got a doc on ChangeMenu?).
5845 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5848 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5851 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5854 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5857 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5858 flags
&~ MF_REMOVE
);
5860 default : /* MF_INSERT */
5861 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);