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
);
18 LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
19 void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
21 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
23 /* internal popup menu window messages */
25 #define MM_SETMENUHANDLE (WM_USER + 0)
26 #define MM_GETMENUHANDLE (WM_USER + 1)
28 /* internal flags for menu tracking */
30 #define TF_ENDMENU 0x10000
31 #define TF_SUSPENDPOPUP 0x20000
32 #define TF_SKIPREMOVE 0x40000
37 /* Internal MenuTrackMenu() flags */
38 #define TPM_INTERNAL 0xF0000000
39 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
40 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
42 /* top and bottom margins for popup menus */
43 #define MENU_TOP_MARGIN 3
44 #define MENU_BOTTOM_MARGIN 2
46 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
48 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
50 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
52 #define MENUITEMINFO_TYPE_MASK \
53 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
54 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
55 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
57 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
59 #define STATE_MASK (~TYPE_MASK)
61 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
63 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
65 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
66 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
67 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
69 #define IS_SYSTEM_MENU(MenuInfo) \
70 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
72 #define IS_SYSTEM_POPUP(MenuInfo) \
73 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
75 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
77 /* Use global popup window because there's no way 2 menus can
78 * be tracked at the same time. */
79 static HWND top_popup
;
80 static HMENU top_popup_hmenu
;
82 /* Flag set by EndMenu() to force an exit from menu tracking */
83 static BOOL fEndMenu
= FALSE
;
85 #define MENU_ITEM_HBMP_SPACE (5)
86 #define MENU_BAR_ITEMS_SPACE (12)
87 #define SEPARATOR_HEIGHT (5)
88 #define MENU_TAB_SPACE (8)
93 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
94 HMENU TopMenu
; /* initial menu */
95 HWND OwnerWnd
; /* where notifications are sent */
100 /*********************************************************************
101 * PopupMenu class descriptor
103 const struct builtin_class_descr POPUPMENU_builtin_class
=
106 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
107 (WNDPROC
) NULL
, /* FIXME - procA */
108 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
109 sizeof(MENUINFO
*), /* extra */
110 (LPCWSTR
) IDC_ARROW
, /* cursor */
111 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
115 #define GET_WORD(ptr) (*(WORD *)(ptr))
118 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
121 HFONT hMenuFont
= NULL
;
122 HFONT hMenuFontBold
= NULL
;
124 /* Dimension of the menu bitmaps */
125 static HBITMAP BmpSysMenu
= NULL
;
127 static SIZE MenuCharSize
;
130 /***********************************************************************
133 * Validate the given menu handle and returns the menu structure pointer.
135 FORCEINLINE PMENU
MENU_GetMenu(HMENU hMenu
)
137 return ValidateHandleNoErr(hMenu
, TYPE_MENU
);
140 /***********************************************************************
143 * Get the system menu of a window
145 static HMENU
get_win_sys_menu( HWND hwnd
)
148 WND
*win
= ValidateHwnd( hwnd
);
151 ret
= win
->SystemMenu
;
156 /***********************************************************************
159 * Find a menu item. Return a pointer on the item, and modifies *hmenu
160 * in case the item was in a sub-menu.
162 ITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
165 ITEM
*fallback
= NULL
;
166 UINT fallback_pos
= 0;
170 if ((*hmenu
== (HMENU
)0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
171 if (wFlags
& MF_BYPOSITION
)
173 if (*nPos
>= menu
->cItems
) return NULL
;
174 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
175 if (pItem
) pItem
= &pItem
[*nPos
];
180 PITEM item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
181 for (i
= 0; item
, i
< menu
->cItems
; i
++, item
++)
185 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
186 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
187 ITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
193 else if (item
->wID
== *nPos
)
195 /* fallback to this item if nothing else found */
200 else if (item
->wID
== *nPos
)
209 *nPos
= fallback_pos
;
214 #define MAX_GOINTOSUBMENU (0x10)
216 IntGetMenuDefaultItem(PMENU Menu
, BOOL fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
219 PITEM Item
= Menu
->rgItems
? DesktopPtrToUser(Menu
->rgItems
) : NULL
;
222 if (!Item
) return -1;
224 while ( !( Item
->fState
& MFS_DEFAULT
) )
227 if (i
>= Menu
->cItems
) return -1;
230 /* default: don't return disabled items */
231 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (Item
->fState
& MFS_DISABLED
)) return -1;
233 /* search rekursiv when needed */
234 if ( (Item
->fType
& MF_POPUP
) && (gmdiFlags
& GMDI_GOINTOPOPUPS
) && Item
->spSubMenu
)
238 ret
= IntGetMenuDefaultItem( DesktopPtrToUser(Item
->spSubMenu
), fByPos
, gmdiFlags
, gismc
);
240 if ( -1 != ret
) return ret
;
242 /* when item not found in submenu, return the popup item */
244 return ( fByPos
) ? i
: Item
->wID
;
247 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
,
250 LPMENUITEMINFOW lpmii
,
253 ITEM
*pItem
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
255 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
259 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
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
& 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
= ValidateHandleNoErr(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 if (ItemInfo
->hSubMenu
)
523 if (!IsMenu(ItemInfo
->hSubMenu
)) ItemInfo
->hSubMenu
= NULL
;
525 Ret
= NtUserThunkedMenuItemInfo(Menu
, Index
, TRUE
, FALSE
, (LPMENUITEMINFOW
)ItemInfo
, NULL
);
529 /***********************************************************************
530 * MenuCleanupRosMenuItemInfo
532 * Cleanup after use of MenuGet/SetRosMenuItemInfo
535 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
537 if (ItemInfo
->dwTypeData
!= NULL
)
539 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
540 ItemInfo
->dwTypeData
= NULL
;
544 /***********************************************************************
545 * MenuInitSysMenuPopup
547 * Grey the appropriate items in System menu.
549 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
557 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
558 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
559 gray
= ((style
& WS_MAXIMIZE
) != 0);
560 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
561 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
562 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
563 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
564 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
565 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
566 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
567 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
569 /* The menu item must keep its state if it's disabled */
571 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
573 /* Set default menu item */
574 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
575 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
576 else DefItem
= SC_CLOSE
;
578 mii
.cbSize
= sizeof(MENUITEMINFOW
);
579 mii
.fMask
|= MIIM_STATE
;
580 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
581 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
583 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
586 /******************************************************************************
588 * UINT MenuGetStartOfNextColumn(
589 * PROSMENUINFO MenuInfo)
591 *****************************************************************************/
593 static UINT
MENU_GetStartOfNextColumn(
596 MENU
*menu
= MENU_GetMenu(hMenu
);
601 return NO_SELECTED_ITEM
;
604 if( i
== NO_SELECTED_ITEM
)
607 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
608 if (!pItem
) return NO_SELECTED_ITEM
;
609 for( ; i
< menu
->cItems
; ++i
) {
610 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
614 return NO_SELECTED_ITEM
;
617 /******************************************************************************
619 * UINT MenuGetStartOfPrevColumn(
620 * PROSMENUINFO MenuInfo)
622 *****************************************************************************/
623 static UINT
MENU_GetStartOfPrevColumn(
626 MENU
*menu
= MENU_GetMenu(hMenu
);
631 return NO_SELECTED_ITEM
;
633 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
634 return NO_SELECTED_ITEM
;
636 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
637 if (!pItem
) return NO_SELECTED_ITEM
;
639 /* Find the start of the column */
641 for(i
= menu
->iItem
; i
!= 0 &&
642 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
646 return NO_SELECTED_ITEM
;
648 for(--i
; i
!= 0; --i
) {
649 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
653 TRACE("ret %d.\n", i
);
658 /***********************************************************************
661 * Load the arrow bitmap. We can't do this from MenuInit since user32
662 * can also be used (and thus initialized) from text-mode.
665 MenuLoadBitmaps(VOID
)
667 /* Load system buttons bitmaps */
668 if (NULL
== BmpSysMenu
)
670 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
673 /////////// Make gpsi OBMI via callback //////////////
674 /***********************************************************************
677 HBITMAP
get_arrow_bitmap(void)
679 static HBITMAP arrow_bitmap
;
681 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
685 /***********************************************************************
686 * get_down_arrow_bitmap DFCS_MENUARROWDOWN
688 HBITMAP
get_down_arrow_bitmap(void)
690 static HBITMAP arrow_bitmap
;
692 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW
));
696 /***********************************************************************
697 * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
699 HBITMAP
get_down_arrow_inactive_bitmap(void)
701 static HBITMAP arrow_bitmap
;
703 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI
));
707 /***********************************************************************
708 * get_up_arrow_bitmap DFCS_MENUARROWUP
710 HBITMAP
get_up_arrow_bitmap(void)
712 static HBITMAP arrow_bitmap
;
714 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW
));
718 /***********************************************************************
719 * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
721 static HBITMAP
get_up_arrow_inactive_bitmap(void)
723 static HBITMAP arrow_bitmap
;
725 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI
));
729 /***********************************************************************
732 * Find a Sub menu. Return the position of the submenu, and modifies
733 * *hmenu in case it is found in another sub-menu.
734 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
736 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
738 PMENU menu
, pSubMenu
;
743 if (((*hmenu
)==(HMENU
)0xffff) ||(!(menu
= MENU_GetMenu(*hmenu
))))
744 return NO_SELECTED_ITEM
;
746 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
747 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
749 if (!item
->spSubMenu
)
753 pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
754 hSubMenu
= UserHMGetHandle(pSubMenu
);
755 if (hSubMenu
== hSubTarget
)
761 HMENU hsubmenu
= hSubMenu
;
762 UINT pos
= MenuFindSubMenu( &hsubmenu
, hSubTarget
);
763 if (pos
!= NO_SELECTED_ITEM
)
771 return NO_SELECTED_ITEM
;
774 /***********************************************************************
775 * MENU_AdjustMenuItemRect
777 * Adjust menu item rectangle according to scrolling state.
780 MENU_AdjustMenuItemRect(PROSMENUINFO menu
, LPRECT rect
)
782 if (menu
->dwArrowsOn
)
784 UINT arrow_bitmap_height
;
787 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp
), &bmp
);
788 arrow_bitmap_height
= bmp
.bmHeight
;
789 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
790 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
794 /***********************************************************************
797 * Draws popup magic glyphs (can be found in system menu).
800 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
803 HFONT hFont
, hOldFont
;
809 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
812 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
815 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
818 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
822 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
825 ZeroMemory(&lf
, sizeof(LOGFONTW
));
826 InflateRect(r
, -2, -2);
827 lf
.lfHeight
= r
->bottom
- r
->top
;
829 lf
.lfWeight
= FW_NORMAL
;
830 lf
.lfCharSet
= DEFAULT_CHARSET
;
831 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
832 hFont
= CreateFontIndirect(&lf
);
833 /* save font and text color */
834 hOldFont
= SelectObject(dc
, hFont
);
835 clrsave
= GetTextColor(dc
);
836 bkmode
= GetBkMode(dc
);
837 /* set color and drawing mode */
838 SetBkMode(dc
, TRANSPARENT
);
844 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
845 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
848 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
849 /* draw selected symbol */
850 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
851 /* restore previous settings */
852 SetTextColor(dc
, clrsave
);
853 SelectObject(dc
, hOldFont
);
854 SetBkMode(dc
, bkmode
);
858 /***********************************************************************
861 * Find the menu item selected by a key press.
862 * Return item id, -1 if none, -2 if we should close the menu.
864 static UINT FASTCALL
MENU_FindItemByKey(HWND WndOwner
, HMENU hmenu
,
865 WCHAR Key
, BOOL ForceMenuChar
)
870 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, hmenu
);
872 if (!IsMenu( hmenu
)) hmenu
= GetSubMenu( get_win_sys_menu(WndOwner
), 0);
875 MENU
*menu
= MENU_GetMenu( hmenu
);
876 ITEM
*item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
881 BOOL cjk
= GetSystemMetrics( SM_DBCSENABLED
);
883 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
885 LPWSTR text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
888 const WCHAR
*p
= text
- 2;
891 const WCHAR
*q
= p
+ 2;
892 p
= strchrW (q
, '&');
893 if (!p
&& cjk
) p
= strchrW (q
, '\036'); /* Japanese Win16 */
895 while (p
!= NULL
&& p
[1] == '&');
896 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
901 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
902 Flags
|= menu
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0;
904 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
905 MAKEWPARAM(Key
, Flags
), (LPARAM
) hmenu
);
906 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
907 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
912 /***********************************************************************
913 * MenuGetBitmapItemSize
915 * Get the size of a bitmap item.
917 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
920 HBITMAP bmp
= lpitem
->hbmpItem
;
922 size
->cx
= size
->cy
= 0;
924 /* check if there is a magic menu item associated with this item */
925 if (IS_MAGIC_BITMAP(bmp
))
927 switch((INT_PTR
) bmp
)
929 case (INT_PTR
)HBMMENU_CALLBACK
:
931 MEASUREITEMSTRUCT measItem
;
932 measItem
.CtlType
= ODT_MENU
;
934 measItem
.itemID
= lpitem
->wID
;
935 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
936 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
937 measItem
.itemData
= lpitem
->dwItemData
;
938 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
939 size
->cx
= measItem
.itemWidth
;
940 size
->cy
= measItem
.itemHeight
;
945 case (INT_PTR
) HBMMENU_SYSTEM
:
946 if (0 != lpitem
->dwItemData
)
948 bmp
= (HBITMAP
) lpitem
->dwItemData
;
952 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
953 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
954 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
955 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
956 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
957 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
958 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
959 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
960 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
961 /* FIXME: Why we need to subtract these magic values? */
962 /* to make them smaller than the menu bar? */
963 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
964 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
969 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
971 size
->cx
= bm
.bmWidth
;
972 size
->cy
= bm
.bmHeight
;
976 /***********************************************************************
979 * Draw a bitmap item.
981 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
982 PROSMENUINFO MenuInfo
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
988 int w
= rect
->right
- rect
->left
;
989 int h
= rect
->bottom
- rect
->top
;
992 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
995 /* Check if there is a magic menu item associated with this item */
996 if (IS_MAGIC_BITMAP(hbmToDraw
))
1002 switch ((INT_PTR
)hbmToDraw
)
1004 case (INT_PTR
)HBMMENU_SYSTEM
:
1005 if (lpitem
->dwTypeData
)
1007 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
1008 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1012 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
1014 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
1015 /* only use right half of the bitmap */
1016 bmp_xoffset
= bm
.bmWidth
/ 2;
1017 bm
.bmWidth
-= bmp_xoffset
;
1020 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1021 flags
= DFCS_CAPTIONRESTORE
;
1023 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1025 flags
= DFCS_CAPTIONMIN
;
1027 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1029 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1031 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1032 flags
= DFCS_CAPTIONCLOSE
;
1034 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1035 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1037 case (INT_PTR
)HBMMENU_CALLBACK
:
1039 DRAWITEMSTRUCT drawItem
;
1041 drawItem
.CtlType
= ODT_MENU
;
1043 drawItem
.itemID
= lpitem
->wID
;
1044 drawItem
.itemAction
= odaction
;
1045 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1046 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1047 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1048 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1049 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1050 //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
1051 //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
1052 drawItem
.hwndItem
= (HWND
)MenuInfo
->Self
;
1054 drawItem
.rcItem
= *rect
;
1055 drawItem
.itemData
= lpitem
->dwItemData
;
1056 /* some applications make this assumption on the DC's origin */
1057 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
1058 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
1059 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1060 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1065 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1066 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1067 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1068 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1069 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1072 InflateRect(&r
, -1, -1);
1073 if (0 != (lpitem
->fState
& MF_HILITE
))
1075 flags
|= DFCS_PUSHED
;
1077 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1081 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1084 hdcMem
= CreateCompatibleDC( hdc
);
1085 SelectObject( hdcMem
, bmp
);
1087 /* handle fontsize > bitmap_height */
1088 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1090 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1091 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
1092 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1093 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
1097 /***********************************************************************
1100 * Calculate the size of the menu item and store it in lpitem->rect.
1102 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
1103 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1106 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1107 UINT arrow_bitmap_width
;
1111 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
1113 GetObjectW( get_arrow_bitmap(), sizeof(bm
), &bm
);
1114 arrow_bitmap_width
= bm
.bmWidth
;
1116 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
1118 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
1120 if (lpitem
->fType
& MF_OWNERDRAW
)
1122 MEASUREITEMSTRUCT mis
;
1123 mis
.CtlType
= ODT_MENU
;
1125 mis
.itemID
= lpitem
->wID
;
1126 mis
.itemData
= lpitem
->dwItemData
;
1127 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1129 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1130 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1131 * width of a menufont character to the width of an owner-drawn menu.
1133 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1135 /* under at least win95 you seem to be given a standard
1136 height for the menu and the height value is ignored */
1137 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1139 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
1141 //Item->cxBmp = mis.itemWidth;
1142 //Item->cyBmp = mis.itemHeight;
1143 TRACE("id=%04lx size=%dx%d\n",
1144 lpitem
->wID
, lpitem
->Rect
.right
-lpitem
->Rect
.left
,
1145 lpitem
->Rect
.bottom
-lpitem
->Rect
.top
);
1149 if (lpitem
->fType
& MF_SEPARATOR
)
1151 lpitem
->Rect
.bottom
+= GetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1153 lpitem
->Rect
.right
+= arrow_bitmap_width
/*check_bitmap_width*/ + MenuCharSize
.cx
;
1159 if (lpitem
->hbmpItem
)
1164 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1165 /* Keep the size of the bitmap in callback mode to be able
1166 * to draw it correctly */
1167 lpitem
->maxBmpSize
= size
;
1168 MenuInfo
->cxTextAlign
= max(MenuInfo
->cxTextAlign
, size
.cx
);
1169 MenuSetRosMenuInfo(MenuInfo
);
1170 lpitem
->Rect
.right
+= size
.cx
+ 2;
1171 itemheight
= size
.cy
+ 2;
1173 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1174 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
1175 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1176 lpitem
->dxTab
= lpitem
->Rect
.right
;
1177 lpitem
->Rect
.right
+= arrow_bitmap_width
;//check_bitmap_width;
1178 } else /* hbmpItem & MenuBar */ {
1179 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1180 lpitem
->Rect
.right
+= size
.cx
;
1181 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
1182 itemheight
= size
.cy
;
1184 /* Special case: Minimize button doesn't have a space behind it. */
1185 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1186 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1187 lpitem
->Rect
.right
-= 1;
1190 else if (!menuBar
) {
1191 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1192 lpitem
->Rect
.right
+= check_bitmap_width
;
1193 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1194 lpitem
->dxTab
= lpitem
->Rect
.right
;
1195 lpitem
->Rect
.right
+= check_bitmap_width
;
1198 /* it must be a text item - unless it's the system menu */
1199 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
1200 HFONT hfontOld
= NULL
;
1201 RECT rc
= lpitem
->Rect
;
1202 LONG txtheight
, txtwidth
;
1204 if ( lpitem
->fState
& MFS_DEFAULT
) {
1205 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1208 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
1209 DT_SINGLELINE
|DT_CALCRECT
);
1210 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
1211 itemheight
= max( max( itemheight
, txtheight
),
1212 GetSystemMetrics( SM_CYMENU
) - 1);
1213 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1215 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
1218 int n
= (int)( p
- lpitem
->dwTypeData
);
1219 /* Item contains a tab (only meaningful in popup menus) */
1220 /* get text size before the tab */
1221 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
1222 DT_SINGLELINE
|DT_CALCRECT
);
1223 txtwidth
= rc
.right
- rc
.left
;
1224 p
+= 1; /* advance past the Tab */
1225 /* get text size after the tab */
1226 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1227 DT_SINGLELINE
|DT_CALCRECT
);
1228 lpitem
->dxTab
+= txtwidth
;
1229 txtheight
= max( txtheight
, tmpheight
);
1230 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1231 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1233 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
1234 DT_SINGLELINE
|DT_CALCRECT
);
1235 txtwidth
= rc
.right
- rc
.left
;
1236 lpitem
->dxTab
+= txtwidth
;
1238 lpitem
->Rect
.right
+= 2 + txtwidth
;
1239 itemheight
= max( itemheight
,
1240 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1242 if (hfontOld
) SelectObject (hdc
, hfontOld
);
1243 } else if( menuBar
) {
1244 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1246 lpitem
->Rect
.bottom
+= itemheight
;
1247 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
1250 /***********************************************************************
1251 * MENU_GetMaxPopupHeight
1254 MENU_GetMaxPopupHeight(PROSMENUINFO lppop
)
1257 return lppop
->cyMax
;
1258 return GetSystemMetrics(SM_CYSCREEN
) - GetSystemMetrics(SM_CYBORDER
);
1261 /***********************************************************************
1262 * MenuPopupMenuCalcSize
1264 * Calculate the size of a popup menu.
1266 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1268 ROSMENUITEMINFO lpitem
;
1271 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1272 BOOL textandbmp
= FALSE
;
1274 MenuInfo
->cxMenu
= MenuInfo
->cyMenu
= 0;
1275 if (MenuInfo
->cItems
== 0)
1277 MenuSetRosMenuInfo(MenuInfo
);
1282 SelectObject( hdc
, hMenuFont
);
1287 MenuInfo
->cxTextAlign
= 0;
1289 MenuInitRosMenuItemInfo(&lpitem
);
1290 while (start
< MenuInfo
->cItems
)
1295 maxTab
= maxTabWidth
= 0;
1297 /* Parse items until column break or end of menu */
1298 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1300 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1302 MenuCleanupRosMenuItemInfo(&lpitem
);
1303 MenuSetRosMenuInfo(MenuInfo
);
1307 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1309 if( lpitem
.lpstr
&& lpitem
.hbmpItem
) textandbmp
= TRUE
;
1311 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
1312 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1314 MenuCleanupRosMenuItemInfo(&lpitem
);
1315 MenuSetRosMenuInfo(MenuInfo
);
1318 // Not sure here,, The patch from wine removes this.
1319 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
1323 maxX
= max(maxX
, lpitem
.Rect
.right
);
1324 orgY
= lpitem
.Rect
.bottom
;
1325 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
1327 maxTab
= max( maxTab
, lpitem
.dxTab
);
1328 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
1332 /* Finish the column (set all items to the largest width found) */
1333 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1336 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
1338 lpitem
.Rect
.right
= maxX
;
1339 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
1341 lpitem
.dxTab
= maxTab
;
1343 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
1347 MenuInfo
->cyMenu
= max(MenuInfo
->cyMenu
, orgY
);
1350 MenuInfo
->cxMenu
= maxX
;
1351 /* if none of the items have both text and bitmap then
1352 * the text and bitmaps are all aligned on the left. If there is at
1353 * least one item with both text and bitmap then bitmaps are
1354 * on the left and texts left aligned with the right hand side
1356 if( !textandbmp
) MenuInfo
->cxTextAlign
= 0;
1358 /* space for 3d border */
1359 MenuInfo
->cyMenu
+= MENU_BOTTOM_MARGIN
;
1360 MenuInfo
->cxMenu
+= 2;
1362 /* Adjust popup height if it exceeds maximum */
1363 maxHeight
= MENU_GetMaxPopupHeight(MenuInfo
);
1364 MenuInfo
->iMaxTop
= MenuInfo
->cyMenu
- MENU_TOP_MARGIN
;
1365 if (MenuInfo
->cyMenu
>= maxHeight
)
1367 MenuInfo
->cyMenu
= maxHeight
;
1368 MenuInfo
->dwArrowsOn
= 1;
1372 MenuInfo
->dwArrowsOn
= 0;
1375 MenuCleanupRosMenuItemInfo(&lpitem
);
1376 MenuSetRosMenuInfo(MenuInfo
);
1377 ReleaseDC( 0, hdc
);
1380 /***********************************************************************
1381 * MenuMenuBarCalcSize
1383 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1384 * height is off by 1 pixel which causes lengthy window relocations when
1385 * active document window is maximized/restored.
1387 * Calculate the size of the menu bar.
1389 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1390 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1392 ROSMENUITEMINFO ItemInfo
;
1393 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1395 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1396 if (MenuInfo
->cItems
== 0) return;
1397 TRACE("lprect %p %s\n", lprect
, wine_dbgstr_rect( lprect
));
1398 MenuInfo
->cxMenu
= lprect
->right
- lprect
->left
;
1399 MenuInfo
->cyMenu
= 0;
1400 maxY
= lprect
->top
+ 1;
1404 MenuInfo
->cxTextAlign
= 0;
1406 MenuInitRosMenuItemInfo(&ItemInfo
);
1407 while (start
< MenuInfo
->cItems
)
1409 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1411 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1414 orgX
= lprect
->left
;
1417 /* Parse items until line break or end of menu */
1418 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1420 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1422 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1424 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1425 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
1426 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1428 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1432 if (ItemInfo
.Rect
.right
> lprect
->right
)
1434 if (i
!= start
) break;
1435 else ItemInfo
.Rect
.right
= lprect
->right
;
1437 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1438 orgX
= ItemInfo
.Rect
.right
;
1439 if (i
+ 1 < MenuInfo
->cItems
)
1441 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1443 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1449 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1450 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1452 /* Finish the line (set all items to the largest height found) */
1455 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1457 ItemInfo
.Rect
.bottom
= maxY
;
1458 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1463 start
= i
; /* This works! */
1467 lprect
->bottom
= maxY
;
1468 MenuInfo
->cyMenu
= lprect
->bottom
- lprect
->top
;
1469 MenuSetRosMenuInfo(MenuInfo
);
1473 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1474 /* the last item (if several lines, only move the last line) */
1475 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->cItems
- 1, &ItemInfo
))
1477 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1480 orgY
= ItemInfo
.Rect
.top
;
1481 orgX
= lprect
->right
;
1482 for (i
= MenuInfo
->cItems
- 1; helpPos
<= i
; i
--)
1488 if (ItemInfo
.Rect
.top
!= orgY
)
1490 break; /* Other line */
1492 if (orgX
<= ItemInfo
.Rect
.right
)
1494 break; /* Too far right already */
1496 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1497 ItemInfo
.Rect
.right
= orgX
;
1498 orgX
= ItemInfo
.Rect
.left
;
1499 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1500 if (helpPos
+ 1 <= i
&&
1501 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1503 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1509 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1512 /***********************************************************************
1513 * MENU_DrawScrollArrows
1515 * Draw scroll arrows.
1518 MENU_DrawScrollArrows(PROSMENUINFO lppop
, HDC hdc
)
1520 HDC hdcMem
= CreateCompatibleDC(hdc
);
1521 HBITMAP hOrigBitmap
;
1522 UINT arrow_bitmap_width
, arrow_bitmap_height
;
1526 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
1527 arrow_bitmap_width
= bmp
.bmWidth
;
1528 arrow_bitmap_height
= bmp
.bmHeight
;
1532 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_bitmap());
1534 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_inactive_bitmap());
1537 rect
.right
= lppop
->cxMenu
;
1538 rect
.bottom
= arrow_bitmap_height
;
1539 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1540 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2, 0,
1541 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1542 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
1543 rect
.bottom
= lppop
->cyMenu
;
1544 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1545 if (lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
))
1546 SelectObject(hdcMem
, get_down_arrow_bitmap());
1548 SelectObject(hdcMem
, get_down_arrow_inactive_bitmap());
1549 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2,
1550 lppop
->cyMenu
- arrow_bitmap_height
,
1551 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1552 SelectObject(hdcMem
, hOrigBitmap
);
1556 /***********************************************************************
1559 * Draw a single menu item.
1561 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1562 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1566 BOOL flat_menu
= FALSE
;
1568 PWND Wnd
= ValidateHwndNoErr(hWnd
);
1573 if (lpitem
->fType
& MF_SYSMENU
)
1575 if ( (Wnd
->style
& WS_MINIMIZE
))
1577 UserGetInsideRectNC(Wnd
, &rect
);
1578 UserDrawSysMenuButton(hWnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1583 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1584 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1588 if (lpitem
->fState
& MF_HILITE
)
1590 if(menuBar
&& !flat_menu
) {
1591 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1592 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1594 if (lpitem
->fState
& MF_GRAYED
)
1595 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1597 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1598 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1603 if (lpitem
->fState
& MF_GRAYED
)
1604 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1606 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1607 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1610 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem
->Rect
));
1611 rect
= lpitem
->Rect
;
1612 MENU_AdjustMenuItemRect(MenuInfo
, &rect
);
1614 if (lpitem
->fType
& MF_OWNERDRAW
)
1617 ** Experimentation under Windows reveals that an owner-drawn
1618 ** menu is given the rectangle which includes the space it requested
1619 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1620 ** and a popup-menu arrow. This is the value of lpitem->rect.
1621 ** Windows will leave all drawing to the application except for
1622 ** the popup-menu arrow. Windows always draws that itself, after
1623 ** the menu owner has finished drawing.
1627 dis
.CtlType
= ODT_MENU
;
1629 dis
.itemID
= lpitem
->wID
;
1630 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1632 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1633 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
1634 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
1635 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1636 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1637 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1638 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1639 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1640 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1643 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1644 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1645 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1646 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1648 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1649 /* Draw the popup-menu arrow */
1650 if (lpitem
->hSubMenu
)
1653 CopyRect(&rectTemp
, &rect
);
1654 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1655 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1660 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1662 if (lpitem
->fState
& MF_HILITE
)
1666 InflateRect (&rect
, -1, -1);
1667 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1668 InflateRect (&rect
, 1, 1);
1669 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1674 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1676 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1680 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1682 SetBkMode( hdc
, TRANSPARENT
);
1684 /* vertical separator */
1685 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1692 rc
.bottom
= Height
- 3;
1695 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1696 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1697 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1698 LineTo( hdc
, rc
.left
, rc
.bottom
);
1699 SelectObject( hdc
, oldPen
);
1702 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1705 /* horizontal separator */
1706 if (lpitem
->fType
& MF_SEPARATOR
)
1713 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1716 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1717 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1718 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1719 LineTo( hdc
, rc
.right
, rc
.top
);
1720 SelectObject( hdc
, oldPen
);
1723 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1728 /* helper lines for debugging */
1729 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1730 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1731 SelectObject(hdc
, GetStockObject(DC_PEN
));
1732 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1733 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1734 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1740 INT y
= rect
.top
+ rect
.bottom
;
1742 BOOL checked
= FALSE
;
1743 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1744 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1745 /* Draw the check mark
1748 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1750 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1751 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1752 lpitem
->hbmpUnchecked
;
1753 if (bm
) /* we have a custom bitmap */
1755 HDC hdcMem
= CreateCompatibleDC( hdc
);
1757 SelectObject( hdcMem
, bm
);
1758 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1759 check_bitmap_width
, check_bitmap_height
,
1760 hdcMem
, 0, 0, SRCCOPY
);
1764 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1767 CopyRect(&r
, &rect
);
1768 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1769 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1770 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1771 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1775 if ( lpitem
->hbmpItem
)
1778 CopyRect(&bmpRect
, &rect
);
1779 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1780 bmpRect
.left
+= check_bitmap_width
+ 2;
1781 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1783 bmpRect
.right
= bmpRect
.left
+ lpitem
->maxBmpSize
.cx
;
1784 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1787 /* Draw the popup-menu arrow */
1788 if (lpitem
->hSubMenu
)
1791 CopyRect(&rectTemp
, &rect
);
1792 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1793 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1796 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1797 rect
.left
+= check_bitmap_width
;
1798 rect
.right
-= check_bitmap_width
;
1800 else if( lpitem
->hbmpItem
)
1801 { /* Draw the bitmap */
1802 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1805 /* process text if present */
1811 UINT uFormat
= menuBar
?
1812 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1813 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1815 if((MenuInfo
->dwStyle
& MNS_CHECKORBMP
))
1816 rect
.left
+= max(0, (int)(MenuInfo
->cxTextAlign
- GetSystemMetrics(SM_CXMENUCHECK
)));
1818 rect
.left
+= MenuInfo
->cxTextAlign
;
1820 if ( lpitem
->fState
& MFS_DEFAULT
)
1822 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1826 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1827 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1830 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1833 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1834 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1838 if(lpitem
->fState
& MF_GRAYED
)
1840 if (!(lpitem
->fState
& MF_HILITE
) )
1842 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1843 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1844 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1845 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1847 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1850 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1852 /* paint the shortcut text */
1853 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1855 if (L
'\t' == Text
[i
])
1857 rect
.left
= lpitem
->dxTab
;
1858 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1862 rect
.right
= lpitem
->dxTab
;
1863 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1866 if (lpitem
->fState
& MF_GRAYED
)
1868 if (!(lpitem
->fState
& MF_HILITE
) )
1870 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1871 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1872 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1873 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1875 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1877 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1881 SelectObject (hdc
, hfontOld
);
1885 /***********************************************************************
1888 * Paint a popup menu.
1890 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1892 HBRUSH hPrevBrush
= 0;
1895 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1897 GetClientRect( hwnd
, &rect
);
1899 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1900 && (SelectObject( hdc
, hMenuFont
)))
1904 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1906 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1909 BOOL flat_menu
= FALSE
;
1910 ROSMENUINFO MenuInfo
;
1911 ROSMENUITEMINFO ItemInfo
;
1913 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1915 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1917 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1919 /* draw menu items */
1920 //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
1921 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.cItems
)
1924 MenuInitRosMenuItemInfo(&ItemInfo
);
1926 for (u
= 0; u
< MenuInfo
.cItems
; u
++)
1928 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1930 HWND WndOwner
= MenuInfo
.spwndNotify
? MenuInfo
.spwndNotify
->head
.h
: NULL
;
1931 MenuDrawMenuItem(hwnd
, &MenuInfo
, WndOwner
, hdc
, &ItemInfo
,
1932 MenuInfo
.cyMenu
, FALSE
, ODA_DRAWENTIRE
);
1936 /* draw scroll arrows */
1937 if (MenuInfo
.dwArrowsOn
)
1938 MENU_DrawScrollArrows(&MenuInfo
, hdc
);
1940 MenuSetRosMenuInfo(&MenuInfo
);
1941 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1945 SelectObject( hdc
, hPrevBrush
);
1950 /***********************************************************************
1953 * Paint a menu bar. Returns the height of the menu bar.
1954 * called from [windows/nonclient.c]
1956 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1961 HMENU hMenu
= GetMenu(hwnd
);
1963 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1965 return GetSystemMetrics(SM_CYMENU
);
1970 hfontOld
= SelectObject(hDC
, hMenuFont
);
1972 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1974 lprect
->bottom
= lprect
->top
+ lppop
.cyMenu
;
1976 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1977 return lppop
.cyMenu
;
1980 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1983 /***********************************************************************
1986 * Popup menu initialization before WM_ENTERMENULOOP.
1988 static BOOL
MENU_InitPopup( HWND hwndOwner
, HMENU hmenu
, UINT flags
)
1992 ROSMENUINFO MenuInfo
;
1994 TRACE("owner=%p hmenu=%p\n", hwndOwner
, hmenu
);
1996 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1998 /* store the owner for DrawItem */
1999 if (!IsWindow( hwndOwner
))
2001 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2004 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
2005 //menu->hwndOwner = hwndOwner;
2006 MenuInfo
.spwndNotify
= ValidateHwndNoErr( hwndOwner
);
2008 if (flags
& TPM_LAYOUTRTL
)
2009 ex_style
= WS_EX_LAYOUTRTL
;
2011 /* NOTE: In Windows, top menu popup is not owned. */
2012 //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2013 MenuInfo
.Wnd
= CreateWindowExW( ex_style
, WC_MENU
, NULL
,
2014 WS_POPUP
, 0, 0, 0, 0,
2015 hwndOwner
, 0, (HINSTANCE
)GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
2017 MenuSetRosMenuInfo(&MenuInfo
);
2018 if( !menu
->hWnd
) return FALSE
;
2022 /***********************************************************************
2025 * Display a popup menu.
2027 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
2028 INT x
, INT y
, INT xanchor
, INT yanchor
)
2030 ROSMENUINFO MenuInfo
;
2031 ROSMENUITEMINFO ItemInfo
;
2037 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2038 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
2040 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
2041 if (MenuInfo
.iItem
!= NO_SELECTED_ITEM
)
2043 MenuInitRosMenuItemInfo(&ItemInfo
);
2044 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
))
2046 ItemInfo
.fMask
|= MIIM_STATE
;
2047 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2048 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
);
2050 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2051 MenuInfo
.iItem
= NO_SELECTED_ITEM
;
2054 //menu->dwArrowsOn = 0;
2055 MenuInfo
.dwArrowsOn
= 0;
2056 MenuSetRosMenuInfo(&MenuInfo
);
2057 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
2059 /* adjust popup menu pos so that it fits within the desktop */
2061 width
= MenuInfo
.cxMenu
+ GetSystemMetrics(SM_CXBORDER
);
2062 height
= MenuInfo
.cyMenu
+ GetSystemMetrics(SM_CYBORDER
);
2064 /* FIXME: should use item rect */
2067 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2068 info
.cbSize
= sizeof(info
);
2069 GetMonitorInfoW( monitor
, &info
);
2071 if (flags
& TPM_LAYOUTRTL
)
2072 flags
^= TPM_RIGHTALIGN
;
2074 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2075 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2077 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2078 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2080 if( x
+ width
> info
.rcMonitor
.right
)
2082 if( xanchor
&& x
>= width
- xanchor
)
2083 x
-= width
- xanchor
;
2085 if( x
+ width
> info
.rcMonitor
.right
)
2086 x
= info
.rcMonitor
.right
- width
;
2088 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
2090 if( y
+ height
> info
.rcMonitor
.bottom
)
2092 if( yanchor
&& y
>= height
+ yanchor
)
2093 y
-= height
+ yanchor
;
2095 if( y
+ height
> info
.rcMonitor
.bottom
)
2096 y
= info
.rcMonitor
.bottom
- height
;
2098 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
2101 top_popup
= MenuInfo
.Wnd
;
2102 top_popup_hmenu
= hmenu
;
2104 /* Display the window */
2106 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, x
, y
, width
, height
,
2107 SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2108 UpdateWindow( MenuInfo
.Wnd
);
2110 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2115 /***********************************************************************
2116 * MENU_EnsureMenuItemVisible
2119 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop
, PROSMENUITEMINFO item
, HDC hdc
)
2121 if (lppop
->dwArrowsOn
)
2123 //ITEM *item = &lppop->items[wIndex];
2124 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2125 UINT nOldPos
= lppop
->iTop
;
2127 UINT arrow_bitmap_height
;
2130 GetClientRect(lppop
->Wnd
, &rc
);
2132 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
2133 arrow_bitmap_height
= bmp
.bmHeight
;
2135 rc
.top
+= arrow_bitmap_height
;
2136 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2138 nMaxHeight
-= GetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2139 if (item
->Rect
.bottom
> lppop
->iTop
+ nMaxHeight
)
2141 lppop
->iTop
= item
->Rect
.bottom
- nMaxHeight
;
2142 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2143 MENU_DrawScrollArrows(lppop
, hdc
);
2145 else if (item
->Rect
.top
- MENU_TOP_MARGIN
< lppop
->iTop
)
2147 lppop
->iTop
= item
->Rect
.top
- MENU_TOP_MARGIN
;
2148 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2149 MENU_DrawScrollArrows(lppop
, hdc
);
2154 /***********************************************************************
2157 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
2158 BOOL sendMenuSelect
, HMENU topmenu
)
2160 ROSMENUITEMINFO ItemInfo
;
2161 ROSMENUINFO TopMenuInfo
;
2164 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
2166 if (!hmenu
|| !hmenu
->cItems
|| !hmenu
->Wnd
) return;
2167 if (hmenu
->iItem
== wIndex
) return;
2168 if (hmenu
->fFlags
& MNF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
2169 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2171 top_popup
= hmenu
->Wnd
;
2172 top_popup_hmenu
= hmenu
->Self
;
2175 SelectObject( hdc
, hMenuFont
);
2177 MenuInitRosMenuItemInfo(&ItemInfo
);
2179 /* Clear previous highlighted item */
2180 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2182 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2184 ItemInfo
.fMask
|= MIIM_STATE
;
2185 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2186 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2188 //MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
2189 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
2190 hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2194 /* Highlight new item (if any) */
2195 hmenu
->iItem
= wIndex
;
2196 MenuSetRosMenuInfo(hmenu
);
2197 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2199 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2201 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
2203 ItemInfo
.fMask
|= MIIM_STATE
;
2204 ItemInfo
.fState
|= MF_HILITE
;
2205 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2206 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
2207 &ItemInfo
, hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2212 WPARAM wParam
= MAKEWPARAM( ItemInfo
.hSubMenu
? wIndex
: ItemInfo
.wID
,
2213 ItemInfo
.fType
| ItemInfo
.fState
|
2214 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2215 (hmenu
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2217 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) hmenu
->Self
);
2221 else if (sendMenuSelect
)
2226 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
2227 if (pos
!= NO_SELECTED_ITEM
)
2229 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
2230 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
2232 WPARAM wParam
= MAKEWPARAM( Pos
, ItemInfo
.fType
| ItemInfo
.fState
|
2233 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2234 (TopMenuInfo
.fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2236 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) topmenu
);
2241 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2242 ReleaseDC(hmenu
->Wnd
, hdc
);
2245 /***********************************************************************
2248 * Moves currently selected item according to the Offset parameter.
2249 * If there is no selection then it should select the last item if
2250 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2252 static void FASTCALL
2253 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2256 ROSMENUITEMINFO ItemInfo
;
2259 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2261 /* Prevent looping */
2262 if (0 == MenuInfo
->cItems
|| 0 == Offset
)
2264 else if (Offset
< -1)
2266 else if (Offset
> 1)
2269 MenuInitRosMenuItemInfo(&ItemInfo
);
2271 OrigPos
= MenuInfo
->iItem
;
2272 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2279 i
= MenuInfo
->iItem
;
2286 /* Clip and wrap around */
2289 i
= MenuInfo
->cItems
- 1;
2291 else if (i
>= MenuInfo
->cItems
)
2295 /* If this is a good candidate; */
2296 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2297 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2299 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2300 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2303 } while (i
!= OrigPos
);
2306 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2311 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2313 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2315 PPOPUPMENU pPopupMenu
;
2317 pWnd
= ValidateHwndNoErr(Wnd
);
2322 if (Message
!= WM_NCCREATE
)
2324 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2326 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2327 pPopupMenu
= HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU
) );
2328 pPopupMenu
->spwndPopupMenu
= pWnd
;
2329 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)pPopupMenu
);
2333 if (pWnd
->fnid
!= FNID_MENU
)
2335 ERR("Wrong window class for Menu!\n");
2338 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
2343 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2349 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2350 pPopupMenu
->spmenu
= ValidateHandle(cs
->lpCreateParams
, TYPE_MENU
);
2354 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2355 return MA_NOACTIVATE
;
2360 BeginPaint(Wnd
, &ps
);
2361 MenuDrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
->head
.h
);
2366 case WM_PRINTCLIENT
:
2368 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
->head
.h
);
2376 /* zero out global pointer in case resident popup window was destroyed. */
2377 if (Wnd
== top_popup
)
2380 top_popup_hmenu
= NULL
;
2386 HeapFree( GetProcessHeap(), 0, pPopupMenu
);
2387 SetWindowLongPtrW(Wnd
, 0, 0);
2388 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2395 if (!pPopupMenu
|| !pPopupMenu
->spmenu
)
2397 OutputDebugStringA("no menu to display\n");
2402 pPopupMenu->spmenu = NULL; ///// WTF?
2406 case MM_SETMENUHANDLE
:
2408 PMENU pmenu
= ValidateHandle((HMENU
)wParam
, TYPE_MENU
);
2411 ERR("Bad Menu Handle\n");
2414 pPopupMenu
->spmenu
= pmenu
;
2418 case MM_GETMENUHANDLE
:
2420 return (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? pPopupMenu
->spmenu
->head
.h
: NULL
) : NULL
);
2423 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2431 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2433 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2436 pWnd
= ValidateHwnd(Wnd
);
2441 if (Message
!= WM_NCCREATE
)
2443 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2445 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2449 if (pWnd
->fnid
!= FNID_MENU
)
2451 ERR("Wrong window class for Menu!\n");
2458 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2464 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2465 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
2469 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2470 return MA_NOACTIVATE
;
2475 BeginPaint(Wnd
, &ps
);
2476 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
2481 case WM_PRINTCLIENT
:
2483 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
2484 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
2492 /* zero out global pointer in case resident popup window was destroyed. */
2493 if (Wnd
== top_popup
)
2496 top_popup_hmenu
= NULL
;
2502 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2509 if (0 == GetWindowLongPtrW(Wnd
, 0))
2511 OutputDebugStringA("no menu to display\n");
2516 SetWindowLongPtrW(Wnd
, 0, 0);
2520 case MM_SETMENUHANDLE
:
2521 SetWindowLongPtrW(Wnd
, 0, wParam
);
2524 case MM_GETMENUHANDLE
:
2526 return GetWindowLongPtrW(Wnd
, 0);
2529 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2536 // This breaks some test results. Should handle A2U if called!
2538 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2542 pWnd
= ValidateHwnd(Wnd
);
2543 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
2545 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2547 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2553 case WM_MOUSEACTIVATE
:
2555 case WM_PRINTCLIENT
:
2560 case MM_SETMENUHANDLE
:
2561 case MM_GETMENUHANDLE
:
2563 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
2566 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2571 /**********************************************************************
2572 * MENU_ParseResource
2574 * Parse a standard menu resource and add items to the menu.
2575 * Return a pointer to the end of the resource.
2577 * NOTE: flags is equivalent to the mtOption field
2579 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2588 flags
= GET_WORD(res
);
2590 /* remove MF_END flag before passing it to AppendMenu()! */
2591 end
= (flags
& MF_END
);
2592 if(end
) flags
^= MF_END
;
2594 res
+= sizeof(WORD
);
2595 if(!(flags
& MF_POPUP
))
2598 res
+= sizeof(WORD
);
2601 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2603 if (flags
& MF_POPUP
)
2605 hSubMenu
= CreatePopupMenu();
2606 if(!hSubMenu
) return NULL
;
2607 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
2608 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
2610 else /* Not a popup */
2612 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2618 /**********************************************************************
2619 * MENUEX_ParseResource
2621 * Parse an extended menu resource and add items to the menu.
2622 * Return a pointer to the end of the resource.
2624 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2631 mii
.cbSize
= sizeof(mii
);
2632 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2633 mii
.fType
= GET_DWORD(res
);
2634 res
+= sizeof(DWORD
);
2635 mii
.fState
= GET_DWORD(res
);
2636 res
+= sizeof(DWORD
);
2637 mii
.wID
= GET_DWORD(res
);
2638 res
+= sizeof(DWORD
);
2639 resinfo
= GET_WORD(res
);
2640 res
+= sizeof(WORD
);
2641 /* Align the text on a word boundary. */
2642 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2643 mii
.dwTypeData
= (LPWSTR
)res
;
2644 mii
.cch
= strlenW(mii
.dwTypeData
);
2645 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2646 /* Align the following fields on a dword boundary. */
2647 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2649 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2650 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2652 if (resinfo
& 1) /* Pop-up? */
2654 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2655 res
+= sizeof(DWORD
);
2656 mii
.hSubMenu
= CreatePopupMenu();
2659 ERR("CreatePopupMenu failed\n");
2663 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2665 ERR("MENUEX_ParseResource failed\n");
2666 DestroyMenu(mii
.hSubMenu
);
2669 mii
.fMask
|= MIIM_SUBMENU
;
2671 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
2673 mii
.fType
|= MF_SEPARATOR
;
2675 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2676 } while (!(resinfo
& MF_END
));
2681 /***********************************************************************
2682 * DrawMenuBarTemp (USER32.@)
2686 * called by W98SE desk.cpl Control Panel Applet
2688 * Not 100% sure about the param names, but close.
2693 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2695 ROSMENUINFO MenuInfo
;
2696 ROSMENUITEMINFO ItemInfo
;
2698 HFONT FontOld
= NULL
;
2699 BOOL flat_menu
= FALSE
;
2701 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2705 Menu
= GetMenu(Wnd
);
2713 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2715 return GetSystemMetrics(SM_CYMENU
);
2718 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2720 FontOld
= SelectObject(DC
, Font
);
2722 if (0 == MenuInfo
.cyMenu
)
2724 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2727 Rect
->bottom
= Rect
->top
+ MenuInfo
.cyMenu
;
2729 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2731 SelectObject(DC
, GetStockObject(DC_PEN
));
2732 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2733 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2734 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2736 if (0 == MenuInfo
.cItems
)
2738 SelectObject(DC
, FontOld
);
2739 return GetSystemMetrics(SM_CYMENU
);
2742 MenuInitRosMenuItemInfo(&ItemInfo
);
2743 for (i
= 0; i
< MenuInfo
.cItems
; i
++)
2745 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2747 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2748 MenuInfo
.cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2751 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2753 SelectObject(DC
, FontOld
);
2755 return MenuInfo
.cyMenu
;
2759 /***********************************************************************
2762 * Display the sub-menu of the selected item of this menu.
2763 * Return the handle of the submenu, or menu if no submenu to display.
2765 static HMENU FASTCALL
2766 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2769 ROSMENUITEMINFO ItemInfo
;
2770 ROSMENUINFO SubMenuInfo
;
2774 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2776 if (NO_SELECTED_ITEM
== MenuInfo
->iItem
)
2778 return MenuInfo
->Self
;
2781 MenuInitRosMenuItemInfo(&ItemInfo
);
2782 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2784 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2785 return MenuInfo
->Self
;
2787 if (0 == (ItemInfo
.hSubMenu
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2789 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2790 return MenuInfo
->Self
;
2793 /* message must be sent before using item,
2794 because nearly everything may be changed by the application ! */
2796 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2797 if (0 == (Flags
& TPM_NONOTIFY
))
2799 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2800 MAKELPARAM(MenuInfo
->iItem
, IS_SYSTEM_MENU(MenuInfo
)));
2803 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2805 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2806 return MenuInfo
->Self
;
2808 Rect
= ItemInfo
.Rect
;
2810 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2811 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2813 if (0 != (MenuInfo
->fFlags
& MNF_POPUP
))
2815 Dc
= GetDC(MenuInfo
->Wnd
);
2819 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2822 SelectObject(Dc
, hMenuFont
);
2823 ItemInfo
.fMask
|= MIIM_STATE
;
2824 ItemInfo
.fState
|= MF_HILITE
;
2825 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2826 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->cyMenu
,
2827 !(MenuInfo
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
2828 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2831 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2832 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2834 ItemInfo
.Rect
= Rect
;
2837 ItemInfo
.fMask
|= MIIM_STATE
;
2838 ItemInfo
.fState
|= MF_MOUSESELECT
;
2839 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2841 if (IS_SYSTEM_MENU(MenuInfo
))
2843 ERR("Right click on window bar and Draw system menu!\n");
2844 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2845 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2846 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
;
2847 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2848 Rect
.top
= Rect
.bottom
;
2849 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2850 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2854 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2855 if (0 != (MenuInfo
->fFlags
& MNF_POPUP
))
2857 RECT rc
= ItemInfo
.Rect
;
2859 MENU_AdjustMenuItemRect(MenuInfo
, &rc
);
2861 if(Flags
& TPM_LAYOUTRTL
)
2862 Rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
2864 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2865 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
2866 Rect
.right
= rc
.left
- rc
.right
+ GetSystemMetrics(SM_CXBORDER
);
2867 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
2868 - GetSystemMetrics(SM_CYBORDER
);
2872 if(Flags
& TPM_LAYOUTRTL
)
2873 Rect
.left
+= Rect
.right
- ItemInfo
.Rect
.left
;
2875 Rect
.left
+= ItemInfo
.Rect
.left
;
2876 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2877 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2878 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2882 /* use default alignment for submenus */
2883 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
2885 MENU_InitPopup( WndOwner
, ItemInfo
.hSubMenu
, Flags
);
2887 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->iItem
, Flags
,
2888 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2889 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2891 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2894 Ret
= ItemInfo
.hSubMenu
;
2895 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2900 /**********************************************************************
2903 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2905 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2907 void MENU_EndMenu( HWND hwnd
)
2910 menu
= top_popup_hmenu
? MENU_GetMenu( top_popup_hmenu
) : NULL
;
2911 if (menu
&& ( hwnd
== menu
->hWnd
|| hwnd
== (menu
->spwndNotify
? menu
->spwndNotify
->head
.h
: NULL
)) )
2915 /***********************************************************************
2918 * Hide the sub-popup menus of this menu.
2920 static void FASTCALL
2921 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2922 BOOL SendMenuSelect
, UINT wFlags
)
2924 ROSMENUINFO SubMenuInfo
;
2925 ROSMENUITEMINFO ItemInfo
;
2927 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2929 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->iItem
)
2931 MenuInitRosMenuItemInfo(&ItemInfo
);
2932 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2933 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
)
2934 || 0 == (ItemInfo
.hSubMenu
)
2935 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2937 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2940 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2941 ItemInfo
.fMask
|= MIIM_STATE
;
2942 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2943 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2945 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2946 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2948 DestroyWindow(SubMenuInfo
.Wnd
);
2949 /* Native returns handle to destroyed window */
2950 if (!(wFlags
& TPM_NONOTIFY
))
2951 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2952 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2954 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
2955 // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
2957 SubMenuInfo
.Wnd
= NULL
;
2958 MenuSetRosMenuInfo(&SubMenuInfo
);
2964 /***********************************************************************
2965 * MenuSwitchTracking
2967 * Helper function for menu navigation routines.
2969 static void FASTCALL
2970 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2972 ROSMENUINFO TopMenuInfo
;
2974 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2976 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2977 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2978 0 == ((PtMenuInfo
->fFlags
| TopMenuInfo
.fFlags
) & MNF_POPUP
))
2980 /* both are top level menus (system and menu-bar) */
2981 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2982 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2983 Mt
->TopMenu
= PtMenuInfo
->Self
;
2987 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2990 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2993 /***********************************************************************
2994 * MenuExecFocusedItem
2996 * Execute a menu item (for instance when user pressed Enter).
2997 * Return the wID of the executed item. Otherwise, -1 indicating
2998 * that no menu item was executed, -2 if a popup is shown;
2999 * Have to receive the flags for the TrackPopupMenu options to avoid
3000 * sending unwanted message.
3004 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
3006 ROSMENUITEMINFO ItemInfo
;
3009 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
3011 if (0 == MenuInfo
->cItems
|| NO_SELECTED_ITEM
== MenuInfo
->iItem
)
3016 MenuInitRosMenuItemInfo(&ItemInfo
);
3017 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3019 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3023 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
3025 if (0 == (ItemInfo
.hSubMenu
))
3027 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
3028 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
3030 /* If TPM_RETURNCMD is set you return the id, but
3031 do not send a message to the owner */
3032 if (0 == (Flags
& TPM_RETURNCMD
))
3034 if (0 != (MenuInfo
->fFlags
& MNF_SYSDESKMN
))
3036 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
3037 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
3041 ROSMENUINFO topmenuI
;
3042 BOOL ret
= MenuGetRosMenuInfo(&topmenuI
, Mt
->TopMenu
);
3043 DWORD dwStyle
= MenuInfo
->dwStyle
| (ret
? topmenuI
.dwStyle
: 0);
3045 if (dwStyle
& MNS_NOTIFYBYPOS
)
3046 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
, MenuInfo
->iItem
, (LPARAM
)MenuInfo
->Self
);
3048 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
3052 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3058 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
3065 /***********************************************************************
3068 * Return TRUE if we can go on with menu tracking.
3070 static BOOL FASTCALL
3071 MENU_ButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
3074 ROSMENUINFO MenuInfo
;
3075 ROSMENUITEMINFO Item
;
3077 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
3081 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3085 if (IS_SYSTEM_MENU(&MenuInfo
))
3091 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3093 MenuInitRosMenuItemInfo(&Item
);
3094 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
3096 MenuCleanupRosMenuItemInfo(&Item
);
3100 if (!(Item
.fType
& MF_SEPARATOR
) &&
3101 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
3103 if (MenuInfo
.iItem
!= Index
)
3105 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3108 /* If the popup menu is not already "popped" */
3109 if (0 == (Item
.fState
& MF_MOUSESELECT
))
3111 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3115 MenuCleanupRosMenuItemInfo(&Item
);
3120 /* else the click was on the menu bar, finish the tracking */
3125 /***********************************************************************
3128 * Return the value of MenuExecFocusedItem if
3129 * the selected item was not a popup. Else open the popup.
3130 * A -1 return value indicates that we go on with menu tracking.
3134 MENU_ButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3137 ROSMENUINFO MenuInfo
;
3138 ROSMENUITEMINFO ItemInfo
;
3140 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
3145 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3150 if (! IS_SYSTEM_MENU(&MenuInfo
))
3152 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3154 MenuInitRosMenuItemInfo(&ItemInfo
);
3155 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
3156 MenuInfo
.iItem
== Id
)
3158 if (0 == (ItemInfo
.hSubMenu
))
3160 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
3161 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3162 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
3164 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3166 /* If we are dealing with the top-level menu */
3167 /* and this is a click on an already "popped" item: */
3168 /* Stop the menu tracking and close the opened submenus */
3169 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
3171 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3175 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3176 MenuInfo
.TimeToHide
= TRUE
;
3177 MenuSetRosMenuInfo(&MenuInfo
);
3183 /***********************************************************************
3186 * Walks menu chain trying to find a menu pt maps to.
3188 static HMENU FASTCALL
3189 MENU_PtMenu(HMENU hMenu
, POINT pt
)
3195 menu
= MENU_GetMenu( hMenu
);
3196 if (!menu
) return NULL
;
3198 /* try subpopup first (if any) */
3199 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3201 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3202 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3203 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3205 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
3206 ret
= MENU_PtMenu( UserHMGetHandle(pSubMenu
), pt
);
3210 /* check the current window (avoiding WM_HITTEST) */
3213 INT ht
= DefWndNCHitTest(menu
->hWnd
, pt
);
3214 if ( menu
->fFlags
& MNF_POPUP
)
3216 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
3218 else if (ht
== HTSYSMENU
)
3219 ret
= NtUserGetSystemMenu(menu
->hWnd
, FALSE
);
3220 else if (ht
== HTMENU
)
3221 ret
= GetMenu( menu
->hWnd
);
3226 /***********************************************************************
3229 * Return TRUE if we can go on with menu tracking.
3231 static BOOL FASTCALL
3232 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3235 ROSMENUINFO MenuInfo
;
3236 ROSMENUITEMINFO ItemInfo
;
3240 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3244 if (IS_SYSTEM_MENU(&MenuInfo
))
3250 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3255 Index
= NO_SELECTED_ITEM
;
3258 if (NO_SELECTED_ITEM
== Index
)
3260 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
3261 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3263 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3267 else if (MenuInfo
.iItem
!= Index
)
3269 MenuInitRosMenuItemInfo(&ItemInfo
);
3270 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
3271 !(ItemInfo
.fType
& MF_SEPARATOR
))
3273 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3274 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
3275 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3277 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3283 /***********************************************************************
3286 * Return the handle of the selected sub-popup menu (if any).
3289 HMENU
MENU_GetSubPopup( HMENU hmenu
)
3294 menu
= MENU_GetMenu( hmenu
);
3296 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3298 //item = &menu->rgItems[menu->iItem];
3299 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3300 if (item
) item
= &item
[menu
->iItem
];
3301 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3303 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
3304 return UserHMGetHandle(pSubMenu
);
3309 /***********************************************************************
3312 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3314 static LRESULT FASTCALL
3315 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
3317 ROSMENUINFO TopMenuInfo
;
3318 ROSMENUINFO MenuInfo
;
3320 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3322 return (LRESULT
) FALSE
;
3325 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.iItem
)
3326 || (VK_RIGHT
== Vk
&& TopMenuInfo
.iItem
== TopMenuInfo
.cItems
- 1))
3328 MDINEXTMENU NextMenu
;
3333 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
3334 NextMenu
.hmenuNext
= NULL
;
3335 NextMenu
.hwndNext
= NULL
;
3336 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3338 TRACE("%p [%p] -> %p [%p]\n",
3339 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3341 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3343 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
3344 NewWnd
= Mt
->OwnerWnd
;
3345 if (IS_SYSTEM_MENU(&TopMenuInfo
))
3347 /* switch to the menu bar */
3349 if (0 != (Style
& WS_CHILD
)
3350 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
3357 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
3361 Id
= MenuInfo
.cItems
- 1;
3364 else if (0 != (Style
& WS_SYSMENU
))
3366 /* switch to the system menu */
3367 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
3374 else /* application returned a new menu to switch to */
3376 NewMenu
= NextMenu
.hmenuNext
;
3377 NewWnd
= NextMenu
.hwndNext
;
3379 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
3381 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
3383 if (0 != (Style
& WS_SYSMENU
)
3384 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
3386 /* get the real system menu */
3387 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
3389 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
3391 /* FIXME: Not sure what to do here;
3392 * perhaps try to track NewMenu as a popup? */
3394 WARN(" -- got confused.\n");
3404 if (NewMenu
!= Mt
->TopMenu
)
3406 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3408 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3410 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3414 if (NewWnd
!= Mt
->OwnerWnd
)
3416 Mt
->OwnerWnd
= NewWnd
;
3417 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
3418 SetCapture(Mt
->OwnerWnd
); // 2
3421 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3422 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3424 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3433 /***********************************************************************
3436 * The idea is not to show the popup if the next input message is
3437 * going to hide it anyway.
3439 static BOOL FASTCALL
3440 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
3444 msg
.hwnd
= Mt
->OwnerWnd
;
3446 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
3447 // Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
3452 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3453 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3455 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3456 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3457 if( msg
.message
== WM_KEYDOWN
&&
3458 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3460 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3466 /* failures go through this */
3467 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3471 /***********************************************************************
3474 * Handle a VK_ESCAPE key event in a menu.
3476 static BOOL FASTCALL
3477 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3479 BOOL EndMenu
= TRUE
;
3480 ROSMENUINFO MenuInfo
;
3481 HMENU MenuTmp
, MenuPrev
;
3483 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3485 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3486 && 0 != (MenuInfo
.fFlags
& MNF_POPUP
))
3488 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3490 /* close topmost popup */
3491 while (MenuTmp
!= Mt
->CurrentMenu
)
3494 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3497 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3499 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3501 Mt
->CurrentMenu
= MenuPrev
;
3509 /***********************************************************************
3512 * Handle a VK_LEFT key event in a menu.
3514 static void FASTCALL
3515 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3517 ROSMENUINFO MenuInfo
;
3518 ROSMENUINFO TopMenuInfo
;
3519 ROSMENUINFO PrevMenuInfo
;
3520 HMENU MenuTmp
, MenuPrev
;
3523 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3525 /* Try to move 1 column left (if possible) */
3526 if ( (PrevCol
= MENU_GetStartOfPrevColumn(Mt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3528 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3530 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3535 /* close topmost popup */
3536 while (MenuTmp
!= Mt
->CurrentMenu
)
3539 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3542 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3546 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3547 Mt
->CurrentMenu
= MenuPrev
;
3549 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3553 if ((MenuPrev
== Mt
->TopMenu
) && !(TopMenuInfo
.fFlags
& MNF_POPUP
))
3555 /* move menu bar selection if no more popups are left */
3557 if (!MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3559 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3562 if (MenuPrev
!= MenuTmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3564 /* A sublevel menu was displayed - display the next one
3565 * unless there is another displacement coming up */
3567 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3568 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3570 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3577 /***********************************************************************
3580 * Handle a VK_RIGHT key event in a menu.
3582 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3585 ROSMENUINFO MenuInfo
;
3586 ROSMENUINFO CurrentMenuInfo
;
3589 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3590 Mt
->CurrentMenu
, Mt
->TopMenu
);
3592 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3593 if ((MenuInfo
.fFlags
& MNF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3595 /* If already displaying a popup, try to display sub-popup */
3597 hmenutmp
= Mt
->CurrentMenu
;
3598 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3600 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3603 /* if subpopup was displayed then we are done */
3604 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3607 /* Check to see if there's another column */
3608 if ( (NextCol
= MENU_GetStartOfNextColumn(Mt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3610 TRACE("Going to %d.\n", NextCol
);
3611 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3613 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3618 if (!(MenuInfo
.fFlags
& MNF_POPUP
)) /* menu bar tracking */
3620 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3622 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3623 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3630 /* try to move to the next item */
3631 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3632 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3634 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3636 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3637 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3639 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3646 /***********************************************************************
3649 * Menu tracking code.
3651 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3652 HWND hwnd
, const RECT
*lprect
)
3655 ROSMENUINFO MenuInfo
;
3656 ROSMENUITEMINFO ItemInfo
;
3659 INT executedMenuId
= -1;
3662 BOOL enterIdleSent
= FALSE
;
3665 mt
.CurrentMenu
= hmenu
;
3671 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3672 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3673 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3677 WARN("Invalid menu handle %p\n", hmenu
); // Error already set in IsMenu.
3681 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3686 if (wFlags
& TPM_BUTTONDOWN
)
3688 /* Get the result in order to start the tracking or not */
3689 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
3690 fEndMenu
= !fRemove
;
3693 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3695 /* owner may not be visible when tracking a popup, so use the menu itself */
3696 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3697 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3698 SetCapture(capture_win
); // 2
3702 BOOL ErrorExit
= FALSE
;
3703 menu
= MENU_GetMenu( mt
.CurrentMenu
);
3704 if (!menu
) /* sometimes happens if I do a window manager close */
3707 /* we have to keep the message in the queue until it's
3708 * clear that menu loop is not over yet. */
3712 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3714 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3715 /* remove the message from the queue */
3716 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3721 if (!ValidateHwndNoErr(mt
.OwnerWnd
) || !ValidateHwndNoErr(MenuInfo
.Wnd
))
3723 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3728 HWND win
= MenuInfo
.fFlags
& MNF_POPUP
? MenuInfo
.Wnd
: NULL
;
3729 enterIdleSent
= TRUE
;
3730 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3736 if (ErrorExit
) break; // Gracefully dropout.
3738 /* check if EndMenu() tried to cancel us, by posting this message */
3739 if (msg
.message
== WM_CANCELMODE
)
3741 /* we are now out of the loop */
3744 /* remove the message from the queue */
3745 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3747 /* break out of internal loop, ala ESCAPE */
3751 TranslateMessage( &msg
);
3754 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3755 enterIdleSent
=FALSE
;
3758 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3761 * Use the mouse coordinates in lParam instead of those in the MSG
3762 * struct to properly handle synthetic messages. They are already
3763 * in screen coordinates.
3765 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3766 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3768 /* Find a menu for this mouse event */
3769 hmenu
= MENU_PtMenu(mt
.TopMenu
, mt
.Pt
);
3773 /* no WM_NC... messages in captured state */
3775 case WM_RBUTTONDBLCLK
:
3776 case WM_RBUTTONDOWN
:
3777 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3779 case WM_LBUTTONDBLCLK
:
3780 case WM_LBUTTONDOWN
:
3781 /* If the message belongs to the menu, removes it from the queue */
3782 /* Else, end menu tracking */
3783 fRemove
= MENU_ButtonDown(&mt
, hmenu
, wFlags
);
3784 fEndMenu
= !fRemove
;
3788 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3791 /* Check if a menu was selected by the mouse */
3794 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
3795 TRACE("executedMenuId %d\n", executedMenuId
);
3797 /* End the loop if executedMenuId is an item ID */
3798 /* or if the job was done (executedMenuId = 0). */
3799 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3801 /* No menu was selected by the mouse */
3802 /* if the function was called by TrackPopupMenu, continue
3803 with the menu tracking. If not, stop it */
3805 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3810 /* the selected menu item must be changed every time */
3811 /* the mouse moves. */
3814 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3816 } /* switch(msg.message) - mouse */
3818 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3820 fRemove
= TRUE
; /* Keyboard messages are always removed */
3834 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3836 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3837 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3842 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3843 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3845 if (!(MenuInfo
.fFlags
& MNF_POPUP
))
3847 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3848 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3850 else /* otherwise try to move selection */
3851 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3856 MenuKeyLeft( &mt
, wFlags
);
3860 MenuKeyRight( &mt
, wFlags
);
3864 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3870 hi
.cbSize
= sizeof(HELPINFO
);
3871 hi
.iContextType
= HELPINFO_MENUITEM
;
3872 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3874 if (MenuInfo
.iItem
== NO_SELECTED_ITEM
)
3878 MenuInitRosMenuItemInfo(&ItemInfo
);
3879 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3883 hi
.iCtrlId
= ItemInfo
.wID
;
3889 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3892 hi
.hItemHandle
= hmenu
;
3893 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3894 hi
.MousePos
= msg
.pt
;
3895 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3902 break; /* WM_KEYDOWN */
3909 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3910 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3912 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3913 fEndMenu
= (executedMenuId
!= -2);
3917 /* Hack to avoid control chars. */
3918 /* We will find a better way real soon... */
3919 if (msg
.wParam
< 32) break;
3921 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
3922 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3923 else if (pos
== (UINT
)-1) MessageBeep(0);
3926 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
, TRUE
, 0);
3927 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3928 fEndMenu
= (executedMenuId
!= -2);
3932 } /* switch(msg.message) - kbd */
3936 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3937 DispatchMessageW( &msg
);
3941 if (!fEndMenu
) fRemove
= TRUE
;
3943 /* finally remove message from the queue */
3945 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3946 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3947 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3950 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3951 SetCapture(NULL
); /* release the capture */
3953 /* If dropdown is still painted and the close box is clicked on
3954 then the menu will be destroyed as part of the DispatchMessage above.
3955 This will then invalidate the menu handle in mt.hTopMenu. We should
3956 check for this first. */
3957 if( IsMenu( mt
.TopMenu
) )
3959 if (IsWindow(mt
.OwnerWnd
))
3961 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3963 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3965 if (MenuInfo
.fFlags
& MNF_POPUP
)
3967 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3968 DestroyWindow(MenuInfo
.Wnd
);
3969 MenuInfo
.Wnd
= NULL
;
3970 MenuSetRosMenuInfo(&MenuInfo
);
3972 if (!(wFlags
& TPM_NONOTIFY
))
3973 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3974 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3976 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3979 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3982 /* Reset the variable for hiding menu */
3983 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3985 MenuInfo
.TimeToHide
= FALSE
;
3986 MenuSetRosMenuInfo(&MenuInfo
);
3990 /* The return value is only used by TrackPopupMenu */
3991 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3992 if (executedMenuId
== -1) executedMenuId
= 0;
3993 return executedMenuId
;
3996 /***********************************************************************
3999 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
4001 ROSMENUINFO MenuInfo
;
4003 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
4007 /* This makes the menus of applications built with Delphi work.
4008 * It also enables menus to be displayed in more than one window,
4009 * but there are some bugs left that need to be fixed in this case.
4011 if (!bPopup
&& (MenuGetRosMenuInfo(&MenuInfo
, hMenu
)))
4013 MenuInfo
.Wnd
= hWnd
;
4014 MenuSetRosMenuInfo(&MenuInfo
);
4016 //if (!bPopup) menu->hWnd = hWnd;
4019 top_popup
= MenuInfo
.Wnd
;//menu->hWnd;
4020 top_popup_hmenu
= hMenu
;
4025 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4026 if (!(wFlags
& TPM_NONOTIFY
))
4027 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
4029 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
4031 if (!(wFlags
& TPM_NONOTIFY
))
4033 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
4034 /* If an app changed/recreated menu bar entries in WM_INITMENU
4035 * menu sizes will be recalculated once the menu created/shown.
4038 if (!MenuInfo
.cyMenu
)
4040 /* app changed/recreated menu bar entries in WM_INITMENU
4041 Recalculate menu sizes else clicks will not work */
4042 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4043 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4048 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4050 MenuInfo
.fFlags
& MNF_SYSDESKMN
? OBJID_SYSMENU
: OBJID_MENU
,
4055 /***********************************************************************
4058 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
4060 TRACE("hwnd=%p\n", hWnd
);
4062 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4063 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
4066 top_popup_hmenu
= NULL
;
4070 /***********************************************************************
4071 * MenuTrackMouseMenuBar
4073 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4075 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
4077 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
4078 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4080 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
4082 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4085 /* map point to parent client coordinates */
4086 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
4087 if (Parent
!= GetDesktopWindow())
4089 ScreenToClient(Parent
, &pt
);
4092 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
4093 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
4094 MenuExitTracking(hWnd
, FALSE
);
4098 /***********************************************************************
4099 * MenuTrackKbdMenuBar
4101 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4103 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
4105 UINT uItem
= NO_SELECTED_ITEM
;
4107 ROSMENUINFO MenuInfo
;
4108 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4110 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
4112 /* find window that has a menu */
4114 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
4115 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
4116 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
4118 /* check if we have to track a system menu */
4120 hTrackMenu
= GetMenu( hwnd
);
4121 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
4123 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
4124 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
4126 wParam
|= HTSYSMENU
; /* prevent item lookup */
4129 if (!IsMenu( hTrackMenu
)) return;
4131 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
4133 /* fetch the window menu again, it may have changed */
4134 hTrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( hwnd
) : GetMenu( hwnd
);
4136 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
4141 if( wChar
&& wChar
!= ' ' )
4143 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4144 if ( uItem
>= (UINT
)(-2) )
4146 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
4147 /* schedule end of menu tracking */
4148 wFlags
|= TF_ENDMENU
;
4153 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
4155 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4157 if( uItem
== NO_SELECTED_ITEM
)
4158 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
4160 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
4164 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
4165 MenuExitTracking( hwnd
, FALSE
);
4168 /**********************************************************************
4169 * TrackPopupMenuEx (USER32.@)
4171 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, int x
, int y
,
4172 HWND hWnd
, LPTPMPARAMS lpTpm
)
4177 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
4178 hMenu
, wFlags
, x
, y
, hWnd
, lpTpm
,
4179 lpTpm
? wine_dbgstr_rect( &lpTpm
->rcExclude
) : "-" );
4181 /* Parameter check */
4182 /* FIXME: this check is performed several times, here and in the called
4183 functions. That could be optimized */
4184 if (!(menu
= MENU_GetMenu( hMenu
)))
4186 SetLastError( ERROR_INVALID_MENU_HANDLE
);
4190 if (IsWindow(menu
->hWnd
))
4192 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4196 if (MENU_InitPopup( hWnd
, hMenu
, wFlags
))
4198 MenuInitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
4200 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4201 if (!(wFlags
& TPM_NONOTIFY
))
4202 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
) hMenu
, 0);
4204 if (MenuShowPopup(hWnd
, hMenu
, 0, wFlags
, x
, y
, 0, 0 ))
4205 ret
= MenuTrackMenu(hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
,
4206 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4207 MenuExitTracking(hWnd
, TRUE
);
4211 ROSMENUINFO MenuInfo
;
4212 if (IsWindow( menu
->hWnd
)) // wine hack around this with their destroy function.
4213 DestroyWindow( menu
->hWnd
); // Fix wrong error return.
4215 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
4217 MenuSetRosMenuInfo(&MenuInfo
);
4219 if (!(wFlags
& TPM_NONOTIFY
))
4220 SendMessageW( hWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)hMenu
,
4221 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4227 /**********************************************************************
4228 * TrackPopupMenu (USER32.@)
4230 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
4231 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
4233 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
4236 /**********************************************************************
4239 * Uses flags, id and text ptr, passed by InsertMenu() and
4240 * ModifyMenu() to setup a MenuItemInfo structure.
4242 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
, LPMENUITEMINFOW pmii
, BOOL Unicode
)
4244 RtlZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
4245 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
4246 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
4247 /* setting bitmap clears text and vice versa */
4248 if( IS_STRING_ITEM(flags
)) {
4249 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
4251 flags
|= MF_SEPARATOR
;
4252 /* Item beginning with a backspace is a help item */
4253 /* FIXME: wrong place, this is only true in win16 */
4266 LPCSTR NewItemA
= (LPCSTR
) str
;
4267 if (*NewItemA
== '\b')
4271 str
= (LPCWSTR
) NewItemA
;
4273 TRACE("A cch %d\n",strlen(NewItemA
));
4276 pmii
->dwTypeData
= (LPWSTR
)str
;
4277 } else if( flags
& MFT_BITMAP
){
4278 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
4279 pmii
->hbmpItem
= (HBITMAP
)str
;
4281 if( flags
& MF_OWNERDRAW
){
4282 pmii
->fMask
|= MIIM_DATA
;
4283 pmii
->dwItemData
= (ULONG_PTR
) str
;
4285 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
4286 pmii
->fMask
|= MIIM_SUBMENU
;
4287 pmii
->hSubMenu
= (HMENU
)id
;
4289 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
4290 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
4291 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
4292 pmii
->wID
= (UINT
)id
;
4295 /**********************************************************************
4296 * MENU_NormalizeMenuItemInfoStruct
4298 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
4299 * check, copy and extend the MENUITEMINFO struct from the version that the application
4300 * supplied to the version used by wine source. */
4301 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
4302 MENUITEMINFOW
*pmii_out
)
4304 /* do we recognize the size? */
4305 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
4306 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
4307 SetLastError( ERROR_INVALID_PARAMETER
);
4310 /* copy the fields that we have */
4311 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
4312 /* if the hbmpItem member is missing then extend */
4313 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
4314 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
4315 pmii_out
->hbmpItem
= NULL
;
4317 /* test for invalid bit combinations */
4318 if( (pmii_out
->fMask
& MIIM_TYPE
&&
4319 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
4320 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
4321 ERR("invalid combination of fMask bits used\n");
4322 /* this does not happen on Win9x/ME */
4323 SetLastError( ERROR_INVALID_PARAMETER
);
4326 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
4327 if( pmii_out
->fMask
& MIIM_TYPE
){
4328 pmii_out
->fMask
|= MIIM_FTYPE
;
4329 if( IS_STRING_ITEM(pmii_out
->fType
)){
4330 pmii_out
->fMask
|= MIIM_STRING
;
4331 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
4332 pmii_out
->fMask
|= MIIM_BITMAP
;
4333 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
4336 if (pmii_out
->fMask
& MIIM_FTYPE
)
4338 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
4339 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
4341 if (pmii_out
->fMask
& MIIM_STATE
)
4342 /* Other menu items having MFS_DEFAULT are not converted
4344 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
4352 NONCLIENTMETRICSW ncm
;
4354 /* get the menu font */
4355 if(!hMenuFont
|| !hMenuFontBold
)
4357 ncm
.cbSize
= sizeof(ncm
);
4358 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
4360 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
4364 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4365 if(hMenuFont
== NULL
)
4367 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
4371 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
4372 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4373 if(hMenuFontBold
== NULL
)
4375 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
4376 DeleteObject(hMenuFont
);
4390 DeleteObject(hMenuFont
);
4396 DeleteObject(hMenuFontBold
);
4397 hMenuFontBold
= NULL
;
4402 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
4404 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
4405 LRESULT Result
= (LRESULT
)hmenu
;
4406 MENUINFO menuinfo
= {0};
4407 MENUITEMINFOW info
= {0};
4409 // removing space for checkboxes from menu
4410 menuinfo
.cbSize
= sizeof(menuinfo
);
4411 menuinfo
.fMask
= MIM_STYLE
;
4412 GetMenuInfo(hmenu
, &menuinfo
);
4413 menuinfo
.dwStyle
|= MNS_CHECKORBMP
; // test_menu_bmp_and_string MNS_CHECKORBMP
4414 SetMenuInfo(hmenu
, &menuinfo
);
4416 // adding bitmaps to menu items
4417 info
.cbSize
= sizeof(info
);
4418 info
.fMask
|= MIIM_BITMAP
;
4419 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
4420 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
4421 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
4422 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
4423 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
4424 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
4425 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
4426 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
4428 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
4432 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
4434 PLOADMENU_CALLBACK_ARGUMENTS Common
;
4437 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
4439 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
4440 IS_INTRESOURCE(Common
->MenuName
[0]) ?
4441 MAKEINTRESOURCE(Common
->MenuName
[0]) :
4442 (LPCWSTR
)&Common
->MenuName
);
4444 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
4448 /* FUNCTIONS *****************************************************************/
4454 AppendMenuA(HMENU hMenu
,
4456 UINT_PTR uIDNewItem
,
4460 UNICODE_STRING UnicodeString
;
4463 RtlInitUnicodeString(&UnicodeString
, 0);
4465 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
4467 /* copy the text string, it wll be one or the other */
4468 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4470 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
4472 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
4475 mii
.dwTypeData
= UnicodeString
.Buffer
;
4476 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4480 TRACE("AMA Handle bitmaps\n");
4482 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
4483 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &UnicodeString
);
4484 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
4492 AppendMenuW(HMENU hMenu
,
4494 UINT_PTR uIDNewItem
,
4498 UNICODE_STRING MenuText
;
4501 RtlInitUnicodeString(&MenuText
, 0);
4503 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
4505 /* copy the text string, it wll be one or the other */
4506 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4508 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
4509 mii
.dwTypeData
= MenuText
.Buffer
;
4510 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4512 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &MenuText
);
4520 CheckMenuItem(HMENU hmenu
,
4528 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4531 if (!(item
= MENU_FindItem( &hmenu
, &uIDCheckItem
, uCheck
))) return -1;
4533 Ret
= item
->fState
& MFS_CHECKED
;
4534 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
4536 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4543 CheckMenuRadioItem(HMENU hMenu
,
4551 PITEM mi_first
= NULL
, mi_check
;
4552 HMENU m_first
, m_check
;
4554 mii
.cbSize
= sizeof( mii
);
4556 for (i
= first
; i
<= last
; i
++)
4563 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
4564 if (!mi_first
) continue;
4565 mi_check
= mi_first
;
4571 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
4572 if (!mi_check
) continue;
4575 if (m_first
!= m_check
) continue;
4576 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
4580 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
4582 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
4583 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
4584 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
4585 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4591 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
4592 if (mi_check
->fState
& MFS_CHECKED
)
4594 mii
.fMask
= MIIM_STATE
;
4595 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
4596 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4610 return NtUserxCreateMenu();
4617 CreatePopupMenu(VOID
)
4620 return NtUserxCreatePopupMenu();
4627 DrawMenuBar(HWND hWnd
)
4629 return NtUserxDrawMenuBar(hWnd
);
4636 EnableMenuItem(HMENU hMenu
,
4640 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4650 guii
.cbSize
= sizeof(GUITHREADINFO
);
4651 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4655 guii
.hwndMenuOwner
!= top_popup
)
4657 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4661 /* if we are in the menu code, and it is active */
4662 if (!fEndMenu
&& top_popup
)
4664 /* terminate the menu handling code */
4667 /* needs to be posted to wakeup the internal menu handler */
4668 /* which will now terminate the menu, in the event that */
4669 /* the main window was minimized, or lost focus, so we */
4670 /* don't end up with an orphaned menu */
4671 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4676 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4679 ROSMENUINFO MenuInfo
;
4680 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4681 // Force bits to be set call server side....
4682 // This alone works and passes all the menu test_menu_hilitemenuitem tests.
4683 if (!NtUserHiliteMenuItem(hWnd
, hMenu
, wItemID
, wHilite
)) return FALSE
;
4684 // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
4686 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
4688 if (MenuInfo
.iItem
== wItemID
) return TRUE
;
4689 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4690 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4692 return TRUE
; // Always returns TRUE!
4701 PWND Wnd
= ValidateHwnd(hWnd
);
4706 return UlongToHandle(Wnd
->IDMenu
);
4712 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4715 Ret
= NtUserGetMenuBarInfo( hwnd
, idObject
, idItem
, pmbi
);
4716 // Reason to move to server side!!!!!
4717 if (!Ret
) return Ret
;
4719 pmbi
->fBarFocused
= top_popup_hmenu
== pmbi
->hMenu
;
4722 pmbi
->fFocused
= pmbi
->fBarFocused
;
4732 GetMenuCheckMarkDimensions(VOID
)
4734 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4735 GetSystemMetrics(SM_CYMENUCHECK
)));
4743 GetMenuContextHelpId(HMENU hmenu
)
4746 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4747 return pMenu
->dwContextHelpId
;
4755 GetMenuDefaultItem(HMENU hMenu
,
4761 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
4764 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
4771 GetMenuInfo(HMENU hmenu
,
4776 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4778 SetLastError(ERROR_INVALID_PARAMETER
);
4782 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4785 if (lpcmi
->fMask
& MIM_BACKGROUND
)
4786 lpcmi
->hbrBack
= pMenu
->hbrBack
;
4788 if (lpcmi
->fMask
& MIM_HELPID
)
4789 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
4791 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
4792 lpcmi
->cyMax
= pMenu
->cyMax
;
4794 if (lpcmi
->fMask
& MIM_MENUDATA
)
4795 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
4797 if (lpcmi
->fMask
& MIM_STYLE
)
4798 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
4807 GetMenuItemCount(HMENU hmenu
)
4810 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4811 return pMenu
->cItems
;
4819 GetMenuItemID(HMENU hMenu
,
4823 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
4824 if (lpmi
->spSubMenu
) return -1;
4836 LPMENUITEMINFOA lpmii
)
4841 if( lpmii
->cbSize
!= sizeof( mii
) &&
4842 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4844 SetLastError( ERROR_INVALID_PARAMETER
);
4847 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4848 mii
.cbSize
= sizeof( mii
);
4849 ret
= GetMenuItemInfo_common (hmenu
,
4852 (LPMENUITEMINFOW
)&mii
,
4854 mii
.cbSize
= lpmii
->cbSize
;
4855 memcpy( lpmii
, &mii
, mii
.cbSize
);
4867 LPMENUITEMINFOW lpmii
)
4871 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4873 SetLastError( ERROR_INVALID_PARAMETER
);
4876 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4877 mii
.cbSize
= sizeof( mii
);
4878 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
4879 mii
.cbSize
= lpmii
->cbSize
;
4880 memcpy( lpmii
, &mii
, mii
.cbSize
);
4896 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
4897 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
4899 if (!pItem
->Xlpstr
&& pItem
->hbmp
) Type
= MFT_BITMAP
;
4901 if (pItem
->spSubMenu
)
4903 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
4904 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
4905 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
4906 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|Type
) & 0xff);
4909 return (pItem
->fType
| pItem
->fState
| Type
);
4926 ////// wine Code, seems to be faster.
4927 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
4929 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
4931 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
4933 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
4937 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
4939 if (!text
) return 0;
4940 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
4941 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
4942 lpString
[nMaxCount
-1] = 0;
4943 TRACE("A returning %s\n", lpString
);
4944 return strlen(lpString
);
4962 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
4964 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
4966 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
4968 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
4972 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
4974 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
4980 lstrcpynW( lpString
, text
, nMaxCount
);
4981 TRACE("W returning %S\n", lpString
);
4982 return strlenW(lpString
);
4995 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
4997 if (pItem
->spSubMenu
)
4999 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
5000 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
5001 if (IsMenu(hsubmenu
)) return hsubmenu
;
5017 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
5019 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
5031 UINT_PTR uIDNewItem
,
5035 UNICODE_STRING UnicodeString
;
5038 RtlInitUnicodeString(&UnicodeString
, 0);
5040 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5042 /* copy the text string, it wll be one or the other */
5043 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5045 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5047 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5050 mii
.dwTypeData
= UnicodeString
.Buffer
;
5051 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5055 TRACE("Handle bitmaps\n");
5057 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &UnicodeString
);
5058 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5071 LPCMENUITEMINFOA lpmii
)
5074 UNICODE_STRING UnicodeString
;
5077 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5079 RtlInitUnicodeString(&UnicodeString
, 0);
5081 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5083 /* copy the text string */
5084 if (((mii
.fMask
& MIIM_STRING
) ||
5085 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5086 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5088 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5090 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5093 mii
.dwTypeData
= UnicodeString
.Buffer
;
5094 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5098 TRACE("Handle bitmaps\n");
5100 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
5101 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5114 LPCMENUITEMINFOW lpmii
)
5117 UNICODE_STRING MenuText
;
5120 /* while we could just pass 'lpmii' to win32k, we make a copy so that
5121 if a bad user passes bad data, we crash his process instead of the
5124 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5126 RtlInitUnicodeString(&MenuText
, 0);
5128 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5130 /* copy the text string */
5131 if (((mii
.fMask
& MIIM_STRING
) ||
5132 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5133 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5135 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
5136 mii
.dwTypeData
= MenuText
.Buffer
;
5137 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5139 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
5152 UINT_PTR uIDNewItem
,
5156 UNICODE_STRING MenuText
;
5159 RtlInitUnicodeString(&MenuText
, 0);
5161 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5163 /* copy the text string, it wll be one or the other */
5164 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5166 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5167 mii
.dwTypeData
= MenuText
.Buffer
;
5168 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5170 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &MenuText
);
5182 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
5190 LoadMenuA(HINSTANCE hInstance
,
5193 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
5194 if (Resource
== NULL
)
5198 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
5205 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
5207 return(LoadMenuIndirectW(lpMenuTemplate
));
5214 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
5217 WORD version
, offset
;
5218 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
5220 version
= GET_WORD(p
);
5225 case 0: /* standard format is version of 0 */
5226 offset
= GET_WORD(p
);
5227 p
+= sizeof(WORD
) + offset
;
5228 if (!(hMenu
= CreateMenu())) return 0;
5229 if (!MENU_ParseResource(p
, hMenu
))
5235 case 1: /* extended format is version of 1 */
5236 offset
= GET_WORD(p
);
5237 p
+= sizeof(WORD
) + offset
;
5238 if (!(hMenu
= CreateMenu())) return 0;
5239 if (!MENUEX_ParseResource(p
, hMenu
))
5241 DestroyMenu( hMenu
);
5246 ERR("Menu template version %d not supported.\n", version
);
5255 LoadMenuW(HINSTANCE hInstance
,
5258 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
5259 if (Resource
== NULL
)
5263 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
5276 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
5288 UINT_PTR uIDNewItem
,
5292 UNICODE_STRING UnicodeString
;
5295 RtlInitUnicodeString(&UnicodeString
, 0);
5297 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5299 /* copy the text string, it wll be one or the other */
5300 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5302 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5304 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5307 mii
.dwTypeData
= UnicodeString
.Buffer
;
5308 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5312 TRACE("Handle bitmaps\n");
5314 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &UnicodeString
);
5315 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5328 UINT_PTR uIDNewItem
,
5332 UNICODE_STRING MenuText
;
5335 RtlInitUnicodeString(&MenuText
, 0);
5337 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5339 /* copy the text string, it wll be one or the other */
5340 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5342 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5343 mii
.dwTypeData
= MenuText
.Buffer
;
5344 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5348 TRACE("Handle bitmaps\n");
5350 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &MenuText
);
5361 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
5376 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
5378 SetLastError(ERROR_INVALID_PARAMETER
);
5382 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5383 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
5395 HBITMAP hBitmapUnchecked
,
5396 HBITMAP hBitmapChecked
)
5398 MENUITEMINFOW uItem
;
5399 memset ( &uItem
, 0, sizeof(uItem
) );
5400 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
5401 uItem
.fMask
= MIIM_CHECKMARKS
;
5402 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5403 uItem
.hbmpChecked
= hBitmapChecked
;
5404 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
5416 LPCMENUITEMINFOA lpmii
)
5419 UNICODE_STRING UnicodeString
;
5422 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
5424 RtlInitUnicodeString(&UnicodeString
, 0);
5426 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5428 * MIIM_STRING == good
5429 * MIIM_TYPE & MFT_STRING == good
5430 * MIIM_STRING & MFT_STRING == good
5431 * MIIM_STRING & MFT_OWNERDRAW == good
5433 if (((mii
.fMask
& MIIM_STRING
) ||
5434 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5435 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5437 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5438 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5440 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5443 mii
.dwTypeData
= UnicodeString
.Buffer
;
5444 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5448 UnicodeString
.Buffer
= NULL
;
5450 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
5451 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
5464 LPCMENUITEMINFOW lpmii
)
5466 MENUITEMINFOW MenuItemInfoW
;
5467 UNICODE_STRING UnicodeString
;
5470 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5472 RtlInitUnicodeString(&UnicodeString
, 0);
5474 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
5476 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5477 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5478 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5479 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
5481 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
5482 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5484 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
5500 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5505 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5508 return NtUserSetSystemMenu(hwnd
, hMenu
);
5512 // Example for the Win32/User32 rewrite.
5513 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5527 return NtUserTrackPopupMenuEx( Menu
,
5532 NULL
); // LPTPMPARAMS is null
5551 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5554 Result
= (ULONG_PTR
)lResult
;
5559 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5578 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5581 Result
= (ULONG_PTR
)lResult
;
5586 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5597 LPCWSTR lpszNewItem
,
5602 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5603 for MF_DELETE. We should check the parameters for all others
5604 MF_* actions also (anybody got a doc on ChangeMenu?).
5607 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5610 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5613 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5616 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5619 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5620 flags
&~ MF_REMOVE
);
5622 default : /* MF_INSERT */
5623 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5640 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5641 for MF_DELETE. We should check the parameters for all others
5642 MF_* actions also (anybody got a doc on ChangeMenu?).
5645 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5648 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5651 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5654 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5657 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5658 flags
&~ MF_REMOVE
);
5660 default : /* MF_INSERT */
5661 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);