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 /* Space between 2 columns */
43 #define MENU_COL_SPACE 4
45 /* top and bottom margins for popup menus */
46 #define MENU_TOP_MARGIN 3
47 #define MENU_BOTTOM_MARGIN 2
49 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
51 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
53 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
55 #define MENUITEMINFO_TYPE_MASK \
56 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
57 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
58 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
60 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
62 #define STATE_MASK (~TYPE_MASK)
64 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
66 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
68 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
69 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
70 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
72 #define IS_SYSTEM_MENU(MenuInfo) \
73 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
75 #define IS_SYSTEM_POPUP(MenuInfo) \
76 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
78 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
80 /* Use global popup window because there's no way 2 menus can
81 * be tracked at the same time. */
82 static HWND top_popup
;
83 static HMENU top_popup_hmenu
;
85 /* Flag set by EndMenu() to force an exit from menu tracking */
86 static BOOL fEndMenu
= FALSE
;
88 #define MENU_ITEM_HBMP_SPACE (5)
89 #define MENU_BAR_ITEMS_SPACE (12)
90 #define SEPARATOR_HEIGHT (5)
91 #define MENU_TAB_SPACE (8)
96 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
97 HMENU TopMenu
; /* initial menu */
98 HWND OwnerWnd
; /* where notifications are sent */
103 /*********************************************************************
104 * PopupMenu class descriptor
106 const struct builtin_class_descr POPUPMENU_builtin_class
=
109 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
110 (WNDPROC
) NULL
, /* FIXME - procA */
111 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
112 sizeof(MENUINFO
*), /* extra */
113 (LPCWSTR
) IDC_ARROW
, /* cursor */
114 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
118 #define GET_WORD(ptr) (*(WORD *)(ptr))
121 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
124 HFONT hMenuFont
= NULL
;
125 HFONT hMenuFontBold
= NULL
;
127 /* Dimension of the menu bitmaps */
128 static HBITMAP BmpSysMenu
= NULL
;
130 static SIZE MenuCharSize
;
133 /***********************************************************************
136 * Validate the given menu handle and returns the menu structure pointer.
138 FORCEINLINE PMENU
MENU_GetMenu(HMENU hMenu
)
140 return ValidateHandleNoErr(hMenu
, TYPE_MENU
);
143 /***********************************************************************
146 * Get the system menu of a window
148 static HMENU
get_win_sys_menu( HWND hwnd
)
151 WND
*win
= ValidateHwnd( hwnd
);
154 ret
= win
->SystemMenu
;
159 /***********************************************************************
162 * Find a menu item. Return a pointer on the item, and modifies *hmenu
163 * in case the item was in a sub-menu.
165 ITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
168 ITEM
*fallback
= NULL
;
169 UINT fallback_pos
= 0;
173 if ((*hmenu
== (HMENU
)0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
174 if (wFlags
& MF_BYPOSITION
)
176 if (*nPos
>= menu
->cItems
) return NULL
;
177 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
178 if (pItem
) pItem
= &pItem
[*nPos
];
183 PITEM item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
184 for (i
= 0; item
, i
< menu
->cItems
; i
++, item
++)
188 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
189 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
190 ITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
196 else if (item
->wID
== *nPos
)
198 /* fallback to this item if nothing else found */
203 else if (item
->wID
== *nPos
)
212 *nPos
= fallback_pos
;
217 #define MAX_GOINTOSUBMENU (0x10)
219 IntGetMenuDefaultItem(PMENU Menu
, BOOL fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
222 PITEM Item
= Menu
->rgItems
? DesktopPtrToUser(Menu
->rgItems
) : NULL
;
225 if (!Item
) return -1;
227 while ( !( Item
->fState
& MFS_DEFAULT
) )
230 if (i
>= Menu
->cItems
) return -1;
233 /* default: don't return disabled items */
234 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (Item
->fState
& MFS_DISABLED
)) return -1;
236 /* search rekursiv when needed */
237 if ( (Item
->fType
& MF_POPUP
) && (gmdiFlags
& GMDI_GOINTOPOPUPS
) && Item
->spSubMenu
)
241 ret
= IntGetMenuDefaultItem( DesktopPtrToUser(Item
->spSubMenu
), fByPos
, gmdiFlags
, gismc
);
243 if ( -1 != ret
) return ret
;
245 /* when item not found in submenu, return the popup item */
247 return ( fByPos
) ? i
: Item
->wID
;
250 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
,
253 LPMENUITEMINFOW lpmii
,
256 ITEM
*pItem
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
258 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
262 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
266 if( lpmii
->fMask
& MIIM_TYPE
)
268 if( lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
270 ERR("invalid combination of fMask bits used\n");
271 /* this does not happen on Win9x/ME */
272 SetLastError( ERROR_INVALID_PARAMETER
);
275 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
276 if( pItem
->hbmp
) lpmii
->fType
|= MFT_BITMAP
;
277 lpmii
->hbmpItem
= pItem
->hbmp
; /* not on Win9x/ME */
278 if( lpmii
->fType
& MFT_BITMAP
)
280 lpmii
->dwTypeData
= (LPWSTR
) pItem
->hbmp
;
283 else if( lpmii
->fType
& (MFT_OWNERDRAW
| MFT_SEPARATOR
))
285 /* this does not happen on Win9x/ME */
286 lpmii
->dwTypeData
= 0;
291 /* copy the text string */
292 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)))
295 { // Very strange this fixes a wine test with a crash.
296 if(lpmii
->dwTypeData
&& lpmii
->cch
&& !(GdiValidateHandle((HGDIOBJ
)lpmii
->dwTypeData
)) )
300 *((WCHAR
*)lpmii
->dwTypeData
) = 0;
302 *((CHAR
*)lpmii
->dwTypeData
) = 0;
308 LPWSTR text
= DesktopPtrToUser(pItem
->Xlpstr
);
312 if(lpmii
->dwTypeData
&& lpmii
->cch
)
313 lstrcpynW(lpmii
->dwTypeData
, text
, lpmii
->cch
);
317 len
= WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
) - 1;
318 if(lpmii
->dwTypeData
&& lpmii
->cch
)
319 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1,
320 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
321 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
- 1] = 0;
323 /* if we've copied a substring we return its length */
324 if(lpmii
->dwTypeData
&& lpmii
->cch
)
325 if (lpmii
->cch
<= len
+ 1)
331 /* return length of string */
332 /* not on Win9x/ME if fType & MFT_BITMAP */
338 if (lpmii
->fMask
& MIIM_FTYPE
)
339 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
341 if (lpmii
->fMask
& MIIM_BITMAP
)
342 lpmii
->hbmpItem
= pItem
->hbmp
;
344 if (lpmii
->fMask
& MIIM_STATE
)
345 lpmii
->fState
= pItem
->fState
& MENUITEMINFO_STATE_MASK
;
347 if (lpmii
->fMask
& MIIM_ID
)
348 lpmii
->wID
= pItem
->wID
;
350 if (lpmii
->fMask
& MIIM_SUBMENU
&& pItem
->spSubMenu
)
352 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
353 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
354 lpmii
->hSubMenu
= hSubMenu
;
358 /* hSubMenu is always cleared
359 * (not on Win9x/ME ) */
363 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
365 lpmii
->hbmpChecked
= pItem
->hbmpChecked
;
366 lpmii
->hbmpUnchecked
= pItem
->hbmpUnchecked
;
368 if (lpmii
->fMask
& MIIM_DATA
)
369 lpmii
->dwItemData
= pItem
->dwItemData
;
374 /***********************************************************************
377 * Get full information about menu
380 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
383 if (!(pMenu
= ValidateHandleNoErr(Menu
, TYPE_MENU
))) return FALSE
;
385 MenuInfo
->hbrBack
= pMenu
->hbrBack
;
386 MenuInfo
->dwContextHelpID
= pMenu
->dwContextHelpId
;
387 MenuInfo
->cyMax
= pMenu
->cyMax
;
388 MenuInfo
->dwMenuData
= pMenu
->dwMenuData
;
389 MenuInfo
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
391 MenuInfo
->cItems
= pMenu
->cItems
;
393 MenuInfo
->iItem
= pMenu
->iItem
;
394 MenuInfo
->cxMenu
= pMenu
->cxMenu
;
395 MenuInfo
->cyMenu
= pMenu
->cyMenu
;
396 MenuInfo
->spwndNotify
= pMenu
->spwndNotify
;
397 MenuInfo
->cxTextAlign
= pMenu
->cxTextAlign
;
398 MenuInfo
->iTop
= pMenu
->iMaxTop
;
399 MenuInfo
->iMaxTop
= pMenu
->iMaxTop
;
400 MenuInfo
->dwArrowsOn
= pMenu
->dwArrowsOn
;
402 MenuInfo
->fFlags
= pMenu
->fFlags
;
403 MenuInfo
->Self
= pMenu
->head
.h
;
404 MenuInfo
->TimeToHide
= pMenu
->TimeToHide
;
405 MenuInfo
->Wnd
= pMenu
->hWnd
;
409 /***********************************************************************
412 * Set full information about menu
415 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
417 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
418 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
420 return NtUserThunkedMenuInfo(MenuInfo
->Self
, (LPCMENUINFO
)MenuInfo
);
423 /***********************************************************************
424 * MenuInitRosMenuItemInfo
426 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
429 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
431 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
432 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
435 /***********************************************************************
436 * MenuGetRosMenuItemInfo
438 * Get full information about a menu item
441 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
444 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
446 if (ItemInfo
->dwTypeData
!= NULL
)
448 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
451 ItemInfo
->dwTypeData
= NULL
;
453 if (!(pItem
= MENU_FindItem(&Menu
, &Index
, MF_BYPOSITION
)))
459 ItemInfo
->fType
= pItem
->fType
;
460 ItemInfo
->hbmpItem
= pItem
->hbmp
;
461 ItemInfo
->hbmpChecked
= pItem
->hbmpChecked
;
462 ItemInfo
->hbmpUnchecked
= pItem
->hbmpUnchecked
;
463 ItemInfo
->dwItemData
= pItem
->dwItemData
;
464 ItemInfo
->wID
= pItem
->wID
;
465 ItemInfo
->fState
= pItem
->fState
;
467 if (pItem
->spSubMenu
)
469 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
470 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
471 ItemInfo
->hSubMenu
= hSubMenu
;
474 ItemInfo
->hSubMenu
= NULL
;
476 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
478 LPWSTR lpstr
= pItem
->lpstr
.Buffer
? DesktopPtrToUser(pItem
->lpstr
.Buffer
) : NULL
;
481 ItemInfo
->cch
= pItem
->lpstr
.Length
/ sizeof(WCHAR
);
483 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0, ItemInfo
->cch
* sizeof(WCHAR
));
484 if (ItemInfo
->dwTypeData
== NULL
)
488 RtlCopyMemory(ItemInfo
->dwTypeData
, lpstr
, min(ItemInfo
->cch
* sizeof(WCHAR
), pItem
->lpstr
.MaximumLength
));
496 ItemInfo
->Rect
.left
= pItem
->xItem
;
497 ItemInfo
->Rect
.top
= pItem
->yItem
;
498 ItemInfo
->Rect
.right
= pItem
->cxItem
; // Do this for now......
499 ItemInfo
->Rect
.bottom
= pItem
->cyItem
;
500 ItemInfo
->dxTab
= pItem
->dxTab
;
501 ItemInfo
->lpstr
= pItem
->lpstr
.Buffer
? DesktopPtrToUser(pItem
->lpstr
.Buffer
) : NULL
;
502 ItemInfo
->maxBmpSize
.cx
= pItem
->cxBmp
;
503 ItemInfo
->maxBmpSize
.cy
= pItem
->cyBmp
;
505 ItemInfo
->fMask
= Save_Mask
;
509 /***********************************************************************
510 * MenuSetRosMenuItemInfo
512 * Set selected information about a menu item, need to set the mask bits.
515 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
519 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
520 ItemInfo
->dwTypeData
!= NULL
)
522 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
524 if (ItemInfo
->hSubMenu
)
526 if (!IsMenu(ItemInfo
->hSubMenu
)) ItemInfo
->hSubMenu
= NULL
;
528 Ret
= NtUserThunkedMenuItemInfo(Menu
, Index
, TRUE
, FALSE
, (LPMENUITEMINFOW
)ItemInfo
, NULL
);
532 /***********************************************************************
533 * MenuCleanupRosMenuItemInfo
535 * Cleanup after use of MenuGet/SetRosMenuItemInfo
538 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
540 if (ItemInfo
->dwTypeData
!= NULL
)
542 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
543 ItemInfo
->dwTypeData
= NULL
;
547 /***********************************************************************
548 * MenuInitSysMenuPopup
550 * Grey the appropriate items in System menu.
552 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
560 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
561 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
562 gray
= ((style
& WS_MAXIMIZE
) != 0);
563 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
564 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
565 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
566 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
567 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
568 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
569 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
570 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
572 /* The menu item must keep its state if it's disabled */
574 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
576 /* Set default menu item */
577 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
578 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
579 else DefItem
= SC_CLOSE
;
581 mii
.cbSize
= sizeof(MENUITEMINFOW
);
582 mii
.fMask
|= MIIM_STATE
;
583 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
584 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
586 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
589 /******************************************************************************
591 * UINT MenuGetStartOfNextColumn(
592 * PROSMENUINFO MenuInfo)
594 *****************************************************************************/
596 static UINT
MENU_GetStartOfNextColumn(
599 MENU
*menu
= MENU_GetMenu(hMenu
);
604 return NO_SELECTED_ITEM
;
607 if( i
== NO_SELECTED_ITEM
)
610 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
611 if (!pItem
) return NO_SELECTED_ITEM
;
612 for( ; i
< menu
->cItems
; ++i
) {
613 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
617 return NO_SELECTED_ITEM
;
620 /******************************************************************************
622 * UINT MenuGetStartOfPrevColumn(
623 * PROSMENUINFO MenuInfo)
625 *****************************************************************************/
626 static UINT
MENU_GetStartOfPrevColumn(
629 MENU
*menu
= MENU_GetMenu(hMenu
);
634 return NO_SELECTED_ITEM
;
636 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
637 return NO_SELECTED_ITEM
;
639 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
640 if (!pItem
) return NO_SELECTED_ITEM
;
642 /* Find the start of the column */
644 for(i
= menu
->iItem
; i
!= 0 &&
645 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
649 return NO_SELECTED_ITEM
;
651 for(--i
; i
!= 0; --i
) {
652 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
656 TRACE("ret %d.\n", i
);
661 /***********************************************************************
664 * Load the arrow bitmap. We can't do this from MenuInit since user32
665 * can also be used (and thus initialized) from text-mode.
668 MenuLoadBitmaps(VOID
)
670 /* Load system buttons bitmaps */
671 if (NULL
== BmpSysMenu
)
673 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
676 /////////// Make gpsi OBMI via callback //////////////
677 /***********************************************************************
680 HBITMAP
get_arrow_bitmap(void)
682 static HBITMAP arrow_bitmap
;
684 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
688 /***********************************************************************
689 * get_down_arrow_bitmap DFCS_MENUARROWDOWN
691 HBITMAP
get_down_arrow_bitmap(void)
693 static HBITMAP arrow_bitmap
;
695 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW
));
699 /***********************************************************************
700 * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
702 HBITMAP
get_down_arrow_inactive_bitmap(void)
704 static HBITMAP arrow_bitmap
;
706 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI
));
710 /***********************************************************************
711 * get_up_arrow_bitmap DFCS_MENUARROWUP
713 HBITMAP
get_up_arrow_bitmap(void)
715 static HBITMAP arrow_bitmap
;
717 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW
));
721 /***********************************************************************
722 * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
724 static HBITMAP
get_up_arrow_inactive_bitmap(void)
726 static HBITMAP arrow_bitmap
;
728 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI
));
732 /***********************************************************************
735 * Find a Sub menu. Return the position of the submenu, and modifies
736 * *hmenu in case it is found in another sub-menu.
737 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
739 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
741 PMENU menu
, pSubMenu
;
746 if (((*hmenu
)==(HMENU
)0xffff) ||(!(menu
= MENU_GetMenu(*hmenu
))))
747 return NO_SELECTED_ITEM
;
749 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
750 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
752 if (!item
->spSubMenu
)
756 pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
757 hSubMenu
= UserHMGetHandle(pSubMenu
);
758 if (hSubMenu
== hSubTarget
)
764 HMENU hsubmenu
= hSubMenu
;
765 UINT pos
= MenuFindSubMenu( &hsubmenu
, hSubTarget
);
766 if (pos
!= NO_SELECTED_ITEM
)
774 return NO_SELECTED_ITEM
;
777 /***********************************************************************
778 * MENU_AdjustMenuItemRect
780 * Adjust menu item rectangle according to scrolling state.
783 MENU_AdjustMenuItemRect(PROSMENUINFO menu
, LPRECT rect
)
785 if (menu
->dwArrowsOn
)
787 UINT arrow_bitmap_height
;
790 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp
), &bmp
);
791 arrow_bitmap_height
= bmp
.bmHeight
;
792 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
793 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
797 /***********************************************************************
800 * Draws popup magic glyphs (can be found in system menu).
803 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
806 HFONT hFont
, hOldFont
;
812 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
815 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
818 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
821 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
825 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
828 ZeroMemory(&lf
, sizeof(LOGFONTW
));
829 InflateRect(r
, -2, -2);
830 lf
.lfHeight
= r
->bottom
- r
->top
;
832 lf
.lfWeight
= FW_NORMAL
;
833 lf
.lfCharSet
= DEFAULT_CHARSET
;
834 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
835 hFont
= CreateFontIndirect(&lf
);
836 /* save font and text color */
837 hOldFont
= SelectObject(dc
, hFont
);
838 clrsave
= GetTextColor(dc
);
839 bkmode
= GetBkMode(dc
);
840 /* set color and drawing mode */
841 SetBkMode(dc
, TRANSPARENT
);
847 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
848 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
851 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
852 /* draw selected symbol */
853 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
854 /* restore previous settings */
855 SetTextColor(dc
, clrsave
);
856 SelectObject(dc
, hOldFont
);
857 SetBkMode(dc
, bkmode
);
861 /***********************************************************************
864 * Find the menu item selected by a key press.
865 * Return item id, -1 if none, -2 if we should close the menu.
867 static UINT FASTCALL
MENU_FindItemByKey(HWND WndOwner
, HMENU hmenu
,
868 WCHAR Key
, BOOL ForceMenuChar
)
873 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, hmenu
);
875 if (!IsMenu( hmenu
)) hmenu
= GetSubMenu( get_win_sys_menu(WndOwner
), 0);
878 MENU
*menu
= MENU_GetMenu( hmenu
);
879 ITEM
*item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
881 if ( !ForceMenuChar
)
884 BOOL cjk
= GetSystemMetrics( SM_DBCSENABLED
);
886 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
888 LPWSTR text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
891 const WCHAR
*p
= text
- 2;
894 const WCHAR
*q
= p
+ 2;
895 p
= strchrW (q
, '&');
896 if (!p
&& cjk
) p
= strchrW (q
, '\036'); /* Japanese Win16 */
898 while (p
!= NULL
&& p
[1] == '&');
899 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
904 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
905 Flags
|= menu
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0;
907 MenuChar
= SendMessageW( WndOwner
, WM_MENUCHAR
,
908 MAKEWPARAM(Key
, Flags
), (LPARAM
) hmenu
);
909 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
910 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
915 /***********************************************************************
916 * MenuGetBitmapItemSize
918 * Get the size of a bitmap item.
920 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
923 HBITMAP bmp
= lpitem
->hbmpItem
;
925 size
->cx
= size
->cy
= 0;
927 /* check if there is a magic menu item associated with this item */
928 if (IS_MAGIC_BITMAP(bmp
))
930 switch((INT_PTR
) bmp
)
932 case (INT_PTR
)HBMMENU_CALLBACK
:
934 MEASUREITEMSTRUCT measItem
;
935 measItem
.CtlType
= ODT_MENU
;
937 measItem
.itemID
= lpitem
->wID
;
938 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
939 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
940 measItem
.itemData
= lpitem
->dwItemData
;
941 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
942 size
->cx
= measItem
.itemWidth
;
943 size
->cy
= measItem
.itemHeight
;
948 case (INT_PTR
) HBMMENU_SYSTEM
:
949 if (0 != lpitem
->dwItemData
)
951 bmp
= (HBITMAP
) lpitem
->dwItemData
;
955 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
956 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
957 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
958 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
959 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
960 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
961 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
962 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
963 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
964 /* FIXME: Why we need to subtract these magic values? */
965 /* to make them smaller than the menu bar? */
966 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
967 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
972 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
974 size
->cx
= bm
.bmWidth
;
975 size
->cy
= bm
.bmHeight
;
979 /***********************************************************************
982 * Draw a bitmap item.
984 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
985 PROSMENUINFO MenuInfo
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
991 int w
= rect
->right
- rect
->left
;
992 int h
= rect
->bottom
- rect
->top
;
995 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
998 /* Check if there is a magic menu item associated with this item */
999 if (IS_MAGIC_BITMAP(hbmToDraw
))
1005 switch ((INT_PTR
)hbmToDraw
)
1007 case (INT_PTR
)HBMMENU_SYSTEM
:
1008 if (lpitem
->dwTypeData
)
1010 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
1011 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1015 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
1017 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
1018 /* only use right half of the bitmap */
1019 bmp_xoffset
= bm
.bmWidth
/ 2;
1020 bm
.bmWidth
-= bmp_xoffset
;
1023 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1024 flags
= DFCS_CAPTIONRESTORE
;
1026 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1028 flags
= DFCS_CAPTIONMIN
;
1030 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1032 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1034 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1035 flags
= DFCS_CAPTIONCLOSE
;
1037 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1038 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1040 case (INT_PTR
)HBMMENU_CALLBACK
:
1042 DRAWITEMSTRUCT drawItem
;
1044 drawItem
.CtlType
= ODT_MENU
;
1046 drawItem
.itemID
= lpitem
->wID
;
1047 drawItem
.itemAction
= odaction
;
1048 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1049 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1050 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1051 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1052 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1053 //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
1054 //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
1055 drawItem
.hwndItem
= (HWND
)MenuInfo
->Self
;
1057 drawItem
.rcItem
= *rect
;
1058 drawItem
.itemData
= lpitem
->dwItemData
;
1059 /* some applications make this assumption on the DC's origin */
1060 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
1061 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
1062 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1063 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1068 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1069 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1070 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1071 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1072 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1075 InflateRect(&r
, -1, -1);
1076 if (0 != (lpitem
->fState
& MF_HILITE
))
1078 flags
|= DFCS_PUSHED
;
1080 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1084 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1087 hdcMem
= CreateCompatibleDC( hdc
);
1088 SelectObject( hdcMem
, bmp
);
1090 /* handle fontsize > bitmap_height */
1091 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1093 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1094 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
1095 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1096 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
1100 /***********************************************************************
1103 * Calculate the size of the menu item and store it in lpitem->rect.
1105 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
1106 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1109 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1110 UINT arrow_bitmap_width
;
1114 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
1116 GetObjectW( get_arrow_bitmap(), sizeof(bm
), &bm
);
1117 arrow_bitmap_width
= bm
.bmWidth
;
1119 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
1121 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
1123 if (lpitem
->fType
& MF_OWNERDRAW
)
1125 MEASUREITEMSTRUCT mis
;
1126 mis
.CtlType
= ODT_MENU
;
1128 mis
.itemID
= lpitem
->wID
;
1129 mis
.itemData
= lpitem
->dwItemData
;
1130 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1132 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1133 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1134 * width of a menufont character to the width of an owner-drawn menu.
1136 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1138 /* under at least win95 you seem to be given a standard
1139 height for the menu and the height value is ignored */
1140 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1142 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
1144 //Item->cxBmp = mis.itemWidth;
1145 //Item->cyBmp = mis.itemHeight;
1146 TRACE("id=%04lx size=%dx%d\n",
1147 lpitem
->wID
, lpitem
->Rect
.right
-lpitem
->Rect
.left
,
1148 lpitem
->Rect
.bottom
-lpitem
->Rect
.top
);
1152 if (lpitem
->fType
& MF_SEPARATOR
)
1154 lpitem
->Rect
.bottom
+= GetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1156 lpitem
->Rect
.right
+= arrow_bitmap_width
/*check_bitmap_width*/ + MenuCharSize
.cx
;
1162 if (lpitem
->hbmpItem
)
1167 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1168 /* Keep the size of the bitmap in callback mode to be able
1169 * to draw it correctly */
1170 lpitem
->maxBmpSize
= size
;
1171 MenuInfo
->cxTextAlign
= max(MenuInfo
->cxTextAlign
, size
.cx
);
1172 MenuSetRosMenuInfo(MenuInfo
);
1173 lpitem
->Rect
.right
+= size
.cx
+ 2;
1174 itemheight
= size
.cy
+ 2;
1176 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1177 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
1178 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1179 lpitem
->dxTab
= lpitem
->Rect
.right
;
1180 lpitem
->Rect
.right
+= arrow_bitmap_width
;//check_bitmap_width;
1181 } else /* hbmpItem & MenuBar */ {
1182 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1183 lpitem
->Rect
.right
+= size
.cx
;
1184 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
1185 itemheight
= size
.cy
;
1187 /* Special case: Minimize button doesn't have a space behind it. */
1188 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1189 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1190 lpitem
->Rect
.right
-= 1;
1193 else if (!menuBar
) {
1194 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1195 lpitem
->Rect
.right
+= check_bitmap_width
;
1196 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1197 lpitem
->dxTab
= lpitem
->Rect
.right
;
1198 lpitem
->Rect
.right
+= check_bitmap_width
;
1201 /* it must be a text item - unless it's the system menu */
1202 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
1203 HFONT hfontOld
= NULL
;
1204 RECT rc
= lpitem
->Rect
;
1205 LONG txtheight
, txtwidth
;
1207 if ( lpitem
->fState
& MFS_DEFAULT
) {
1208 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1211 txtheight
= DrawTextW( hdc
, lpitem
->lpstr
, -1, &rc
,
1212 DT_SINGLELINE
|DT_CALCRECT
);
1213 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
1214 itemheight
= max( max( itemheight
, txtheight
),
1215 GetSystemMetrics( SM_CYMENU
) - 1);
1216 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1218 if ((p
= strchrW( lpitem
->lpstr
, '\t' )) != NULL
) {
1221 int n
= (int)( p
- lpitem
->lpstr
);
1222 /* Item contains a tab (only meaningful in popup menus) */
1223 /* get text size before the tab */
1224 txtheight
= DrawTextW( hdc
, lpitem
->lpstr
, n
, &rc
,
1225 DT_SINGLELINE
|DT_CALCRECT
);
1226 txtwidth
= rc
.right
- rc
.left
;
1227 p
+= 1; /* advance past the Tab */
1228 /* get text size after the tab */
1229 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1230 DT_SINGLELINE
|DT_CALCRECT
);
1231 lpitem
->dxTab
+= txtwidth
;
1232 txtheight
= max( txtheight
, tmpheight
);
1233 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1234 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1236 txtheight
= DrawTextW( hdc
, lpitem
->lpstr
, -1, &rc
,
1237 DT_SINGLELINE
|DT_CALCRECT
);
1238 txtwidth
= rc
.right
- rc
.left
;
1239 lpitem
->dxTab
+= txtwidth
;
1241 lpitem
->Rect
.right
+= 2 + txtwidth
;
1242 itemheight
= max( itemheight
,
1243 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1245 if (hfontOld
) SelectObject (hdc
, hfontOld
);
1246 } else if( menuBar
) {
1247 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1249 lpitem
->Rect
.bottom
+= itemheight
;
1250 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
1253 /***********************************************************************
1254 * MENU_GetMaxPopupHeight
1257 MENU_GetMaxPopupHeight(PROSMENUINFO lppop
)
1260 return lppop
->cyMax
;
1261 return GetSystemMetrics(SM_CYSCREEN
) - GetSystemMetrics(SM_CYBORDER
);
1264 /***********************************************************************
1265 * MenuPopupMenuCalcSize
1267 * Calculate the size of a popup menu.
1269 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1271 ROSMENUITEMINFO lpitem
;
1274 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1275 BOOL textandbmp
= FALSE
;
1277 MenuInfo
->cxMenu
= MenuInfo
->cyMenu
= 0;
1278 if (MenuInfo
->cItems
== 0)
1280 MenuSetRosMenuInfo(MenuInfo
);
1285 SelectObject( hdc
, hMenuFont
);
1290 MenuInfo
->cxTextAlign
= 0;
1292 MenuInitRosMenuItemInfo(&lpitem
);
1293 //MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
1294 while (start
< MenuInfo
->cItems
)
1296 //lpitem = &lppop->items[start];
1298 //if( lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))
1299 // orgX += MENU_COL_SPACE;
1300 orgY
= 2;//MENU_TOP_MARGIN;
1302 maxTab
= maxTabWidth
= 0;
1303 /* Parse items until column break or end of menu */
1304 for (i
= start
; i
< MenuInfo
->cItems
; i
++)//, lpitem++)
1306 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1308 MenuCleanupRosMenuItemInfo(&lpitem
);
1309 MenuSetRosMenuInfo(MenuInfo
);
1313 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1316 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
1317 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1319 MenuCleanupRosMenuItemInfo(&lpitem
);
1320 MenuSetRosMenuInfo(MenuInfo
);
1324 maxX
= max(maxX
, lpitem
.Rect
.right
);
1325 orgY
= lpitem
.Rect
.bottom
;
1326 if (IS_STRING_ITEM(lpitem
.fType
) && lpitem
.dxTab
)
1328 maxTab
= max( maxTab
, lpitem
.dxTab
);
1329 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
1331 if( lpitem
.lpstr
&& lpitem
.hbmpItem
) textandbmp
= TRUE
;
1334 /* Finish the column (set all items to the largest width found) */
1335 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1338 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
1340 lpitem
.Rect
.right
= maxX
;
1341 if (IS_STRING_ITEM(lpitem
.fType
) && lpitem
.dxTab
)
1343 lpitem
.dxTab
= maxTab
;
1345 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
1349 MenuInfo
->cyMenu
= max(MenuInfo
->cyMenu
, orgY
);
1352 MenuInfo
->cxMenu
= maxX
;
1353 /* if none of the items have both text and bitmap then
1354 * the text and bitmaps are all aligned on the left. If there is at
1355 * least one item with both text and bitmap then bitmaps are
1356 * on the left and texts left aligned with the right hand side
1358 if( !textandbmp
) MenuInfo
->cxTextAlign
= 0;
1360 /* space for 3d border */
1361 MenuInfo
->cyMenu
+= MENU_BOTTOM_MARGIN
;
1362 MenuInfo
->cxMenu
+= 2;
1364 /* Adjust popup height if it exceeds maximum */
1365 maxHeight
= MENU_GetMaxPopupHeight(MenuInfo
);
1366 MenuInfo
->iMaxTop
= MenuInfo
->cyMenu
- MENU_TOP_MARGIN
;
1367 if (MenuInfo
->cyMenu
>= maxHeight
)
1369 MenuInfo
->cyMenu
= maxHeight
;
1370 MenuInfo
->dwArrowsOn
= 1;
1374 MenuInfo
->dwArrowsOn
= 0;
1377 MenuCleanupRosMenuItemInfo(&lpitem
);
1378 MenuSetRosMenuInfo(MenuInfo
);
1379 ReleaseDC( 0, hdc
);
1382 /***********************************************************************
1383 * MenuMenuBarCalcSize
1385 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1386 * height is off by 1 pixel which causes lengthy window relocations when
1387 * active document window is maximized/restored.
1389 * Calculate the size of the menu bar.
1391 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1392 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1394 ROSMENUITEMINFO ItemInfo
;
1395 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1397 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1398 if (MenuInfo
->cItems
== 0) return;
1399 TRACE("lprect %p %s\n", lprect
, wine_dbgstr_rect( lprect
));
1400 MenuInfo
->cxMenu
= lprect
->right
- lprect
->left
;
1401 MenuInfo
->cyMenu
= 0;
1402 maxY
= lprect
->top
+ 1;
1406 MenuInfo
->cxTextAlign
= 0;
1408 MenuInitRosMenuItemInfo(&ItemInfo
);
1409 while (start
< MenuInfo
->cItems
)
1411 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1413 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1416 orgX
= lprect
->left
;
1419 /* Parse items until line break or end of menu */
1420 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1422 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1424 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1426 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1427 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
1428 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1430 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1434 if (ItemInfo
.Rect
.right
> lprect
->right
)
1436 if (i
!= start
) break;
1437 else ItemInfo
.Rect
.right
= lprect
->right
;
1439 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1440 orgX
= ItemInfo
.Rect
.right
;
1441 if (i
+ 1 < MenuInfo
->cItems
)
1443 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1445 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1451 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1452 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1454 /* Finish the line (set all items to the largest height found) */
1457 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1459 ItemInfo
.Rect
.bottom
= maxY
;
1460 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1465 start
= i
; /* This works! */
1469 lprect
->bottom
= maxY
;
1470 MenuInfo
->cyMenu
= lprect
->bottom
- lprect
->top
;
1471 MenuSetRosMenuInfo(MenuInfo
);
1475 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1476 /* the last item (if several lines, only move the last line) */
1477 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->cItems
- 1, &ItemInfo
))
1479 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1482 orgY
= ItemInfo
.Rect
.top
;
1483 orgX
= lprect
->right
;
1484 for (i
= MenuInfo
->cItems
- 1; helpPos
<= i
; i
--)
1486 if (i
< helpPos
) break; /* done */
1487 if (ItemInfo
.Rect
.top
!= orgY
) break; /* Other line */
1488 if (orgX
<= ItemInfo
.Rect
.right
) break; /* Too far right already */
1489 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1490 ItemInfo
.Rect
.right
= orgX
;
1491 orgX
= ItemInfo
.Rect
.left
;
1492 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1493 if (helpPos
+ 1 <= i
&&
1494 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1496 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1502 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1505 /***********************************************************************
1506 * MENU_DrawScrollArrows
1508 * Draw scroll arrows.
1511 MENU_DrawScrollArrows(PROSMENUINFO lppop
, HDC hdc
)
1513 HDC hdcMem
= CreateCompatibleDC(hdc
);
1514 HBITMAP hOrigBitmap
;
1515 UINT arrow_bitmap_width
, arrow_bitmap_height
;
1519 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
1520 arrow_bitmap_width
= bmp
.bmWidth
;
1521 arrow_bitmap_height
= bmp
.bmHeight
;
1524 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_bitmap());
1526 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_inactive_bitmap());
1529 rect
.right
= lppop
->cxMenu
;
1530 rect
.bottom
= arrow_bitmap_height
;
1531 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1532 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2, 0,
1533 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1534 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
1535 rect
.bottom
= lppop
->cyMenu
;
1536 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1537 if (lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
))
1538 SelectObject(hdcMem
, get_down_arrow_bitmap());
1540 SelectObject(hdcMem
, get_down_arrow_inactive_bitmap());
1541 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2,
1542 lppop
->cyMenu
- arrow_bitmap_height
,
1543 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1544 SelectObject(hdcMem
, hOrigBitmap
);
1548 /***********************************************************************
1551 * Draws the popup-menu arrow.
1553 static void draw_popup_arrow( HDC hdc
, RECT rect
, UINT arrow_bitmap_width
,
1554 UINT arrow_bitmap_height
)
1556 HDC hdcMem
= CreateCompatibleDC( hdc
);
1557 HBITMAP hOrigBitmap
;
1559 hOrigBitmap
= SelectObject( hdcMem
, get_arrow_bitmap() );
1560 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1561 (rect
.top
+ rect
.bottom
- arrow_bitmap_height
) / 2,
1562 arrow_bitmap_width
, arrow_bitmap_height
,
1563 hdcMem
, 0, 0, SRCCOPY
);
1564 SelectObject( hdcMem
, hOrigBitmap
);
1568 /***********************************************************************
1571 * Draw a single menu item.
1573 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1574 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1578 BOOL flat_menu
= FALSE
;
1580 UINT arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
1581 PWND Wnd
= ValidateHwndNoErr(hWnd
);
1588 GetObjectW( get_arrow_bitmap(), sizeof(bmp
), &bmp
);
1589 arrow_bitmap_width
= bmp
.bmWidth
;
1590 arrow_bitmap_height
= bmp
.bmHeight
;
1593 if (lpitem
->fType
& MF_SYSMENU
)
1595 if ( (Wnd
->style
& WS_MINIMIZE
))
1597 UserGetInsideRectNC(Wnd
, &rect
);
1598 UserDrawSysMenuButton(hWnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1603 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1604 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1608 if (lpitem
->fState
& MF_HILITE
)
1610 if(menuBar
&& !flat_menu
) {
1611 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1612 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1614 if (lpitem
->fState
& MF_GRAYED
)
1615 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1617 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1618 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1623 if (lpitem
->fState
& MF_GRAYED
)
1624 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1626 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1627 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1630 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem
->Rect
));
1631 rect
= lpitem
->Rect
;
1632 MENU_AdjustMenuItemRect(MenuInfo
, &rect
);
1634 if (lpitem
->fType
& MF_OWNERDRAW
)
1637 ** Experimentation under Windows reveals that an owner-drawn
1638 ** menu is given the rectangle which includes the space it requested
1639 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1640 ** and a popup-menu arrow. This is the value of lpitem->rect.
1641 ** Windows will leave all drawing to the application except for
1642 ** the popup-menu arrow. Windows always draws that itself, after
1643 ** the menu owner has finished drawing.
1647 dis
.CtlType
= ODT_MENU
;
1649 dis
.itemID
= lpitem
->wID
;
1650 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1652 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1653 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
1654 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
1655 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1656 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1657 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1658 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1659 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1660 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1663 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1664 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1665 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1666 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1668 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1669 /* Draw the popup-menu arrow */
1670 if (lpitem
->hSubMenu
)
1673 CopyRect(&rectTemp, &rect);
1674 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1675 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1677 draw_popup_arrow( hdc
, rect
, arrow_bitmap_width
, arrow_bitmap_height
);
1682 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1684 if (lpitem
->fState
& MF_HILITE
)
1688 InflateRect (&rect
, -1, -1);
1689 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1690 InflateRect (&rect
, 1, 1);
1691 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1696 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1698 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1702 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1704 SetBkMode( hdc
, TRANSPARENT
);
1706 /* vertical separator */
1707 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1712 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1;
1714 rc
.bottom
= Height
- 3;
1717 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1718 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1719 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1720 LineTo( hdc
, rc
.left
, rc
.bottom
);
1721 SelectObject( hdc
, oldPen
);
1724 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1727 /* horizontal separator */
1728 if (lpitem
->fType
& MF_SEPARATOR
)
1735 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1738 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1739 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1740 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1741 LineTo( hdc
, rc
.right
, rc
.top
);
1742 SelectObject( hdc
, oldPen
);
1745 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1750 /* helper lines for debugging */
1751 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1752 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1753 SelectObject(hdc
, GetStockObject(DC_PEN
));
1754 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1755 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1756 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1762 INT y
= rect
.top
+ rect
.bottom
;
1764 BOOL checked
= FALSE
;
1765 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1766 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1767 /* Draw the check mark
1770 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1772 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1773 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1774 lpitem
->hbmpUnchecked
;
1775 if (bm
) /* we have a custom bitmap */
1777 HDC hdcMem
= CreateCompatibleDC( hdc
);
1779 SelectObject( hdcMem
, bm
);
1780 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1781 check_bitmap_width
, check_bitmap_height
,
1782 hdcMem
, 0, 0, SRCCOPY
);
1786 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1789 //HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1790 //HDC hdcMem = CreateCompatibleDC( hdc );
1791 //SelectObject( hdcMem, bm );
1792 //SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
1793 CopyRect(&r
, &rect
);
1794 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1795 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1796 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1797 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1798 //BitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom, hdcMem, 0, 0, SRCCOPY );
1799 //DeleteDC( hdcMem );
1800 //DeleteObject( bm );
1804 if ( lpitem
->hbmpItem
)//&& !( checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
1807 CopyRect(&bmpRect
, &rect
);
1808 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1809 bmpRect
.left
+= check_bitmap_width
+ 2;
1810 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1813 bmpRect
.right
= bmpRect
.left
+ lpitem
->maxBmpSize
.cx
;
1814 /* some applications make this assumption on the DC's origin */
1815 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1816 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1817 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1820 /* Draw the popup-menu arrow */
1821 if (lpitem
->hSubMenu
)
1824 CopyRect(&rectTemp, &rect);
1825 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1826 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1828 draw_popup_arrow( hdc
, rect
, arrow_bitmap_width
, arrow_bitmap_height
);
1831 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1832 rect
.left
+= check_bitmap_width
;
1833 rect
.right
-= arrow_bitmap_width
;//check_bitmap_width;
1835 else if( lpitem
->hbmpItem
)
1836 { /* Draw the bitmap */
1839 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1840 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1841 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1844 /* process text if present */
1849 UINT uFormat
= menuBar
?
1850 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1851 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1853 if((MenuInfo
->dwStyle
& MNS_CHECKORBMP
))
1854 rect
.left
+= max(0, (int)(MenuInfo
->cxTextAlign
- GetSystemMetrics(SM_CXMENUCHECK
)));
1856 rect
.left
+= MenuInfo
->cxTextAlign
;
1858 if ( lpitem
->fState
& MFS_DEFAULT
)
1860 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1864 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1865 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1868 Text
= lpitem
->lpstr
;
1871 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1872 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1876 if(lpitem
->fState
& MF_GRAYED
)
1878 if (!(lpitem
->fState
& MF_HILITE
) )
1880 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1881 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1882 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1883 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1885 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1888 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1890 /* paint the shortcut text */
1891 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1893 if (L
'\t' == Text
[i
])
1895 rect
.left
= lpitem
->dxTab
;
1896 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1900 rect
.right
= lpitem
->dxTab
;
1901 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1904 if (lpitem
->fState
& MF_GRAYED
)
1906 if (!(lpitem
->fState
& MF_HILITE
) )
1908 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1909 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1910 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1911 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1913 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1915 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1919 SelectObject (hdc
, hfontOld
);
1923 /***********************************************************************
1926 * Paint a popup menu.
1928 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1930 HBRUSH hPrevBrush
= 0;
1933 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1935 GetClientRect( hwnd
, &rect
);
1937 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1938 && (SelectObject( hdc
, hMenuFont
)))
1942 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1944 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1947 BOOL flat_menu
= FALSE
;
1948 ROSMENUINFO MenuInfo
;
1949 ROSMENUITEMINFO ItemInfo
;
1951 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1953 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1955 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1957 //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
1958 /* draw menu items */
1959 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.cItems
)
1962 MenuInitRosMenuItemInfo(&ItemInfo
);
1964 for (u
= 0; u
< MenuInfo
.cItems
; u
++)
1966 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1968 HWND WndOwner
= MenuInfo
.spwndNotify
? MenuInfo
.spwndNotify
->head
.h
: NULL
;
1969 MenuDrawMenuItem(hwnd
, &MenuInfo
, WndOwner
, hdc
, &ItemInfo
,
1970 MenuInfo
.cyMenu
, FALSE
, ODA_DRAWENTIRE
);
1973 /* draw scroll arrows */
1974 if (MenuInfo
.dwArrowsOn
)
1975 MENU_DrawScrollArrows(&MenuInfo
, hdc
);
1977 MenuSetRosMenuInfo(&MenuInfo
);
1978 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1982 SelectObject( hdc
, hPrevBrush
);
1987 /***********************************************************************
1990 * Paint a menu bar. Returns the height of the menu bar.
1991 * called from [windows/nonclient.c]
1993 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1998 HMENU hMenu
= GetMenu(hwnd
);
2000 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
2002 return GetSystemMetrics(SM_CYMENU
);
2007 hfontOld
= SelectObject(hDC
, hMenuFont
);
2009 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
2011 lprect
->bottom
= lprect
->top
+ lppop
.cyMenu
;
2013 if (hfontOld
) SelectObject( hDC
, hfontOld
);
2014 return lppop
.cyMenu
;
2017 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
2020 /***********************************************************************
2023 * Popup menu initialization before WM_ENTERMENULOOP.
2025 static BOOL
MENU_InitPopup( HWND hwndOwner
, HMENU hmenu
, UINT flags
)
2028 DWORD ex_style
= WS_EX_TOOLWINDOW
;
2029 ROSMENUINFO MenuInfo
;
2031 TRACE("owner=%p hmenu=%p\n", hwndOwner
, hmenu
);
2033 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2035 /* store the owner for DrawItem */
2036 if (!IsWindow( hwndOwner
))
2038 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2041 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
2042 //menu->hwndOwner = hwndOwner;
2043 MenuInfo
.spwndNotify
= ValidateHwndNoErr( hwndOwner
);
2045 if (flags
& TPM_LAYOUTRTL
)
2046 ex_style
= WS_EX_LAYOUTRTL
;
2048 /* NOTE: In Windows, top menu popup is not owned. */
2049 //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2050 MenuInfo
.Wnd
= CreateWindowExW( ex_style
, WC_MENU
, NULL
,
2051 WS_POPUP
, 0, 0, 0, 0,
2052 hwndOwner
, 0, (HINSTANCE
)GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
2054 MenuSetRosMenuInfo(&MenuInfo
);
2055 if( !menu
->hWnd
) return FALSE
;
2059 /***********************************************************************
2062 * Display a popup menu.
2064 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
2065 INT x
, INT y
, INT xanchor
, INT yanchor
)
2067 ROSMENUINFO MenuInfo
;
2068 ROSMENUITEMINFO ItemInfo
;
2074 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2075 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
2077 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
2078 if (MenuInfo
.iItem
!= NO_SELECTED_ITEM
)
2080 MenuInitRosMenuItemInfo(&ItemInfo
);
2081 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
))
2083 ItemInfo
.fMask
|= MIIM_STATE
;
2084 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2085 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
);
2087 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2088 MenuInfo
.iItem
= NO_SELECTED_ITEM
;
2091 //menu->dwArrowsOn = 0;
2092 MenuInfo
.dwArrowsOn
= 0;
2093 MenuSetRosMenuInfo(&MenuInfo
);
2094 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
2096 /* adjust popup menu pos so that it fits within the desktop */
2098 width
= MenuInfo
.cxMenu
+ GetSystemMetrics(SM_CXBORDER
);
2099 height
= MenuInfo
.cyMenu
+ GetSystemMetrics(SM_CYBORDER
);
2101 /* FIXME: should use item rect */
2104 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2105 info
.cbSize
= sizeof(info
);
2106 GetMonitorInfoW( monitor
, &info
);
2108 if (flags
& TPM_LAYOUTRTL
)
2109 flags
^= TPM_RIGHTALIGN
;
2111 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2112 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2114 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2115 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2117 if( x
+ width
> info
.rcMonitor
.right
)
2119 if( xanchor
&& x
>= width
- xanchor
)
2120 x
-= width
- xanchor
;
2122 if( x
+ width
> info
.rcMonitor
.right
)
2123 x
= info
.rcMonitor
.right
- width
;
2125 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
2127 if( y
+ height
> info
.rcMonitor
.bottom
)
2129 if( yanchor
&& y
>= height
+ yanchor
)
2130 y
-= height
+ yanchor
;
2132 if( y
+ height
> info
.rcMonitor
.bottom
)
2133 y
= info
.rcMonitor
.bottom
- height
;
2135 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
2138 top_popup
= MenuInfo
.Wnd
;
2139 top_popup_hmenu
= hmenu
;
2141 /* Display the window */
2143 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, x
, y
, width
, height
,
2144 SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2145 UpdateWindow( MenuInfo
.Wnd
);
2147 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2152 /***********************************************************************
2153 * MENU_EnsureMenuItemVisible
2156 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop
, PROSMENUITEMINFO item
, HDC hdc
)
2158 if (lppop
->dwArrowsOn
)
2160 //ITEM *item = &lppop->items[wIndex];
2161 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2162 UINT nOldPos
= lppop
->iTop
;
2164 UINT arrow_bitmap_height
;
2167 GetClientRect(lppop
->Wnd
, &rc
);
2169 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
2170 arrow_bitmap_height
= bmp
.bmHeight
;
2172 rc
.top
+= arrow_bitmap_height
;
2173 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2175 nMaxHeight
-= GetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2176 if (item
->Rect
.bottom
> lppop
->iTop
+ nMaxHeight
)
2178 lppop
->iTop
= item
->Rect
.bottom
- nMaxHeight
;
2179 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2180 MENU_DrawScrollArrows(lppop
, hdc
);
2182 else if (item
->Rect
.top
- MENU_TOP_MARGIN
< lppop
->iTop
)
2184 lppop
->iTop
= item
->Rect
.top
- MENU_TOP_MARGIN
;
2185 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2186 MENU_DrawScrollArrows(lppop
, hdc
);
2191 /***********************************************************************
2194 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
2195 BOOL sendMenuSelect
, HMENU topmenu
)
2197 ROSMENUITEMINFO ItemInfo
;
2198 ROSMENUINFO TopMenuInfo
;
2201 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
2203 if (!hmenu
|| !hmenu
->cItems
|| !hmenu
->Wnd
) return;
2204 if (hmenu
->iItem
== wIndex
) return;
2205 if (hmenu
->fFlags
& MNF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
2206 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2208 top_popup
= hmenu
->Wnd
;
2209 top_popup_hmenu
= hmenu
->Self
;
2212 SelectObject( hdc
, hMenuFont
);
2214 MenuInitRosMenuItemInfo(&ItemInfo
);
2216 /* Clear previous highlighted item */
2217 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2219 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2221 ItemInfo
.fMask
|= MIIM_STATE
;
2222 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2223 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2225 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
2226 hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2230 /* Highlight new item (if any) */
2231 hmenu
->iItem
= wIndex
;
2232 MenuSetRosMenuInfo(hmenu
);
2233 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2235 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2237 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
2239 ItemInfo
.fMask
|= MIIM_STATE
;
2240 ItemInfo
.fState
|= MF_HILITE
;
2241 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2242 MENU_EnsureMenuItemVisible(hmenu
, &ItemInfo
, hdc
);
2243 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
2244 &ItemInfo
, hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
2248 WPARAM wParam
= MAKEWPARAM( ItemInfo
.hSubMenu
? wIndex
: ItemInfo
.wID
,
2249 ItemInfo
.fType
| ItemInfo
.fState
|
2250 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2251 (hmenu
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2253 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) hmenu
->Self
);
2257 else if (sendMenuSelect
)
2262 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
2263 if (pos
!= NO_SELECTED_ITEM
)
2265 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
2266 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
2268 WPARAM wParam
= MAKEWPARAM( Pos
, ItemInfo
.fType
| ItemInfo
.fState
|
2269 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2270 (TopMenuInfo
.fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2272 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) topmenu
);
2277 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2278 ReleaseDC(hmenu
->Wnd
, hdc
);
2281 /***********************************************************************
2284 * Moves currently selected item according to the Offset parameter.
2285 * If there is no selection then it should select the last item if
2286 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2288 static void FASTCALL
2289 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2292 ROSMENUITEMINFO ItemInfo
;
2295 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2297 /* Prevent looping */
2298 if (0 == MenuInfo
->cItems
|| 0 == Offset
)
2300 else if (Offset
< -1)
2302 else if (Offset
> 1)
2305 MenuInitRosMenuItemInfo(&ItemInfo
);
2307 OrigPos
= MenuInfo
->iItem
;
2308 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2315 i
= MenuInfo
->iItem
;
2322 /* Clip and wrap around */
2325 i
= MenuInfo
->cItems
- 1;
2327 else if (i
>= MenuInfo
->cItems
)
2331 /* If this is a good candidate; */
2332 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2333 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2335 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2336 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2339 } while (i
!= OrigPos
);
2342 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2347 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2349 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2351 PPOPUPMENU pPopupMenu
;
2353 pWnd
= ValidateHwndNoErr(Wnd
);
2358 if (Message
!= WM_NCCREATE
)
2360 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2362 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2363 pPopupMenu
= HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU
) );
2364 pPopupMenu
->spwndPopupMenu
= pWnd
;
2365 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)pPopupMenu
);
2369 if (pWnd
->fnid
!= FNID_MENU
)
2371 ERR("Wrong window class for Menu!\n");
2374 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
2379 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2385 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2386 pPopupMenu
->spmenu
= ValidateHandle(cs
->lpCreateParams
, TYPE_MENU
);
2390 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2391 return MA_NOACTIVATE
;
2396 BeginPaint(Wnd
, &ps
);
2397 MenuDrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
->head
.h
);
2402 case WM_PRINTCLIENT
:
2404 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
->head
.h
);
2412 /* zero out global pointer in case resident popup window was destroyed. */
2413 if (Wnd
== top_popup
)
2416 top_popup_hmenu
= NULL
;
2422 HeapFree( GetProcessHeap(), 0, pPopupMenu
);
2423 SetWindowLongPtrW(Wnd
, 0, 0);
2424 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2431 if (!pPopupMenu
|| !pPopupMenu
->spmenu
)
2433 OutputDebugStringA("no menu to display\n");
2438 pPopupMenu->spmenu = NULL; ///// WTF?
2442 case MM_SETMENUHANDLE
:
2444 PMENU pmenu
= ValidateHandle((HMENU
)wParam
, TYPE_MENU
);
2447 ERR("Bad Menu Handle\n");
2450 pPopupMenu
->spmenu
= pmenu
;
2454 case MM_GETMENUHANDLE
:
2456 return (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? pPopupMenu
->spmenu
->head
.h
: NULL
) : NULL
);
2459 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2467 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2469 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2472 pWnd
= ValidateHwnd(Wnd
);
2477 if (Message
!= WM_NCCREATE
)
2479 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2481 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2485 if (pWnd
->fnid
!= FNID_MENU
)
2487 ERR("Wrong window class for Menu!\n");
2494 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2500 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2501 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
2505 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2506 return MA_NOACTIVATE
;
2511 BeginPaint(Wnd
, &ps
);
2512 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
2517 case WM_PRINTCLIENT
:
2519 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
2520 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
2528 /* zero out global pointer in case resident popup window was destroyed. */
2529 if (Wnd
== top_popup
)
2532 top_popup_hmenu
= NULL
;
2538 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2545 if (0 == GetWindowLongPtrW(Wnd
, 0))
2547 OutputDebugStringA("no menu to display\n");
2552 SetWindowLongPtrW(Wnd
, 0, 0);
2556 case MM_SETMENUHANDLE
:
2557 SetWindowLongPtrW(Wnd
, 0, wParam
);
2560 case MM_GETMENUHANDLE
:
2562 return GetWindowLongPtrW(Wnd
, 0);
2565 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2572 // This breaks some test results. Should handle A2U if called!
2574 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2578 pWnd
= ValidateHwnd(Wnd
);
2579 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
2581 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2583 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2589 case WM_MOUSEACTIVATE
:
2591 case WM_PRINTCLIENT
:
2596 case MM_SETMENUHANDLE
:
2597 case MM_GETMENUHANDLE
:
2599 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
2602 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2607 /**********************************************************************
2608 * MENU_ParseResource
2610 * Parse a standard menu resource and add items to the menu.
2611 * Return a pointer to the end of the resource.
2613 * NOTE: flags is equivalent to the mtOption field
2615 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2624 flags
= GET_WORD(res
);
2626 /* remove MF_END flag before passing it to AppendMenu()! */
2627 end
= (flags
& MF_END
);
2628 if(end
) flags
^= MF_END
;
2630 res
+= sizeof(WORD
);
2631 if(!(flags
& MF_POPUP
))
2634 res
+= sizeof(WORD
);
2637 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2639 if (flags
& MF_POPUP
)
2641 hSubMenu
= CreatePopupMenu();
2642 if(!hSubMenu
) return NULL
;
2643 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
2644 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
2646 else /* Not a popup */
2648 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2654 /**********************************************************************
2655 * MENUEX_ParseResource
2657 * Parse an extended menu resource and add items to the menu.
2658 * Return a pointer to the end of the resource.
2660 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2667 mii
.cbSize
= sizeof(mii
);
2668 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2669 mii
.fType
= GET_DWORD(res
);
2670 res
+= sizeof(DWORD
);
2671 mii
.fState
= GET_DWORD(res
);
2672 res
+= sizeof(DWORD
);
2673 mii
.wID
= GET_DWORD(res
);
2674 res
+= sizeof(DWORD
);
2675 resinfo
= GET_WORD(res
);
2676 res
+= sizeof(WORD
);
2677 /* Align the text on a word boundary. */
2678 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2679 mii
.dwTypeData
= (LPWSTR
)res
;
2680 mii
.cch
= strlenW(mii
.dwTypeData
);
2681 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2682 /* Align the following fields on a dword boundary. */
2683 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2685 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2686 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2688 if (resinfo
& 1) /* Pop-up? */
2690 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2691 res
+= sizeof(DWORD
);
2692 mii
.hSubMenu
= CreatePopupMenu();
2695 ERR("CreatePopupMenu failed\n");
2699 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2701 ERR("MENUEX_ParseResource failed\n");
2702 DestroyMenu(mii
.hSubMenu
);
2705 mii
.fMask
|= MIIM_SUBMENU
;
2707 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
2709 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2710 mii
.wID
, mii
.fType
);
2711 mii
.fType
|= MF_SEPARATOR
;
2713 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2714 } while (!(resinfo
& MF_END
));
2719 /***********************************************************************
2720 * DrawMenuBarTemp (USER32.@)
2724 * called by W98SE desk.cpl Control Panel Applet
2726 * Not 100% sure about the param names, but close.
2731 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2733 ROSMENUINFO MenuInfo
;
2734 ROSMENUITEMINFO ItemInfo
;
2736 HFONT FontOld
= NULL
;
2737 BOOL flat_menu
= FALSE
;
2739 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2743 Menu
= GetMenu(Wnd
);
2751 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2753 return GetSystemMetrics(SM_CYMENU
);
2756 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2758 FontOld
= SelectObject(DC
, Font
);
2760 if (0 == MenuInfo
.cyMenu
)
2762 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2765 Rect
->bottom
= Rect
->top
+ MenuInfo
.cyMenu
;
2767 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2769 SelectObject(DC
, GetStockObject(DC_PEN
));
2770 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2771 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2772 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2774 if (0 == MenuInfo
.cItems
)
2776 SelectObject(DC
, FontOld
);
2777 return GetSystemMetrics(SM_CYMENU
);
2780 MenuInitRosMenuItemInfo(&ItemInfo
);
2781 for (i
= 0; i
< MenuInfo
.cItems
; i
++)
2783 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2785 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2786 MenuInfo
.cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2789 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2791 SelectObject(DC
, FontOld
);
2793 return MenuInfo
.cyMenu
;
2797 /***********************************************************************
2800 * Display the sub-menu of the selected item of this menu.
2801 * Return the handle of the submenu, or menu if no submenu to display.
2803 static HMENU FASTCALL
2804 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2807 ROSMENUITEMINFO ItemInfo
;
2808 ROSMENUINFO SubMenuInfo
;
2812 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2814 if (MenuInfo
->iItem
== NO_SELECTED_ITEM
) return MenuInfo
->Self
;
2816 MenuInitRosMenuItemInfo(&ItemInfo
);
2817 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2819 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2820 return MenuInfo
->Self
;
2823 //item = &menu->rgItems[menu->iItem];
2824 if (!(ItemInfo
.hSubMenu
) || (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2826 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2827 return MenuInfo
->Self
;
2830 /* message must be sent before using item,
2831 because nearly everything may be changed by the application ! */
2833 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2834 if (!(Flags
& TPM_NONOTIFY
))
2836 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2837 MAKELPARAM(MenuInfo
->iItem
, IS_SYSTEM_MENU(MenuInfo
)));
2840 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2842 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2843 return MenuInfo
->Self
;
2846 //item = &menu->rgItems[menu->iItem];
2847 Rect
= ItemInfo
.Rect
;
2849 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2850 if (!(ItemInfo
.fState
& MF_HILITE
))
2852 if (MenuInfo
->fFlags
& MNF_POPUP
) Dc
= GetDC(MenuInfo
->Wnd
);
2853 else Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2855 SelectObject(Dc
, hMenuFont
);
2856 ItemInfo
.fMask
|= MIIM_STATE
;
2857 ItemInfo
.fState
|= MF_HILITE
;
2858 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2859 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->cyMenu
,
2860 !(MenuInfo
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
2861 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2864 if (!ItemInfo
.Rect
.top
&& !ItemInfo
.Rect
.left
&& !ItemInfo
.Rect
.bottom
&& !ItemInfo
.Rect
.right
)
2865 ItemInfo
.Rect
= Rect
;
2867 ItemInfo
.fMask
|= MIIM_STATE
;
2868 ItemInfo
.fState
|= MF_MOUSESELECT
;
2869 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2871 if (IS_SYSTEM_MENU(MenuInfo
))
2873 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
,
2874 GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2875 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2877 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2878 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
2879 Rect
.top
= Rect
.bottom
;
2880 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2881 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2885 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2886 if (MenuInfo
->fFlags
& MNF_POPUP
)
2888 RECT rc
= ItemInfo
.Rect
;
2890 MENU_AdjustMenuItemRect(MenuInfo
, &rc
);
2892 /* The first item in the popup menu has to be at the
2893 same y position as the focused menu item */
2894 if(Flags
& TPM_LAYOUTRTL
)
2895 Rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
2897 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - GetSystemMetrics(SM_CXBORDER
);
2898 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
2899 Rect
.right
= rc
.left
- rc
.right
+ GetSystemMetrics(SM_CXBORDER
);
2900 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
2901 - GetSystemMetrics(SM_CYBORDER
);
2905 if(Flags
& TPM_LAYOUTRTL
)
2906 Rect
.left
+= Rect
.right
- ItemInfo
.Rect
.left
;
2908 Rect
.left
+= ItemInfo
.Rect
.left
;
2909 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2910 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2911 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2915 /* use default alignment for submenus */
2916 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
2918 MENU_InitPopup( WndOwner
, ItemInfo
.hSubMenu
, Flags
);
2920 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->iItem
, Flags
,
2921 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2922 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2924 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2927 Ret
= ItemInfo
.hSubMenu
;
2928 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2933 /**********************************************************************
2936 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2938 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2940 void MENU_EndMenu( HWND hwnd
)
2943 menu
= top_popup_hmenu
? MENU_GetMenu( top_popup_hmenu
) : NULL
;
2944 if (menu
&& ( hwnd
== menu
->hWnd
|| hwnd
== (menu
->spwndNotify
? menu
->spwndNotify
->head
.h
: NULL
)) )
2948 /***********************************************************************
2951 * Hide the sub-popup menus of this menu.
2953 static void FASTCALL
2954 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2955 BOOL SendMenuSelect
, UINT wFlags
)
2957 ROSMENUINFO SubMenuInfo
;
2958 ROSMENUITEMINFO ItemInfo
;
2960 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2962 if (MenuInfo
&& top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->iItem
)
2964 //item = &menu->rgItems[menu->iItem];
2965 MenuInitRosMenuItemInfo(&ItemInfo
);
2966 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2967 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
)
2968 || !(ItemInfo
.hSubMenu
)
2969 || !(ItemInfo
.fState
& MF_MOUSESELECT
))
2971 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2974 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2975 ItemInfo
.fMask
|= MIIM_STATE
;
2976 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2977 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2979 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2980 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2982 DestroyWindow(SubMenuInfo
.Wnd
);
2983 /* Native returns handle to destroyed window */
2984 if (!(wFlags
& TPM_NONOTIFY
))
2985 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2986 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2988 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
2989 // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
2991 SubMenuInfo
.Wnd
= NULL
;
2992 MenuSetRosMenuInfo(&SubMenuInfo
);
2998 /***********************************************************************
2999 * MenuSwitchTracking
3001 * Helper function for menu navigation routines.
3003 static void FASTCALL
3004 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
3006 ROSMENUINFO TopMenuInfo
;
3008 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
3010 if ( MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
3011 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
3012 !((PtMenuInfo
->fFlags
| TopMenuInfo
.fFlags
) & MNF_POPUP
) )
3014 /* both are top level menus (system and menu-bar) */
3015 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3016 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3017 Mt
->TopMenu
= PtMenuInfo
->Self
;
3021 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
3024 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
3027 /***********************************************************************
3028 * MenuExecFocusedItem
3030 * Execute a menu item (for instance when user pressed Enter).
3031 * Return the wID of the executed item. Otherwise, -1 indicating
3032 * that no menu item was executed, -2 if a popup is shown;
3033 * Have to receive the flags for the TrackPopupMenu options to avoid
3034 * sending unwanted message.
3038 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
3040 ROSMENUITEMINFO ItemInfo
;
3043 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
3045 if (0 == MenuInfo
->cItems
|| NO_SELECTED_ITEM
== MenuInfo
->iItem
)
3050 MenuInitRosMenuItemInfo(&ItemInfo
);
3051 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3053 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3057 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
3059 if (0 == (ItemInfo
.hSubMenu
))
3061 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
3062 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
3064 /* If TPM_RETURNCMD is set you return the id, but
3065 do not send a message to the owner */
3066 if (0 == (Flags
& TPM_RETURNCMD
))
3068 if (0 != (MenuInfo
->fFlags
& MNF_SYSDESKMN
))
3070 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
3071 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
3075 ROSMENUINFO topmenuI
;
3076 BOOL ret
= MenuGetRosMenuInfo(&topmenuI
, Mt
->TopMenu
);
3077 DWORD dwStyle
= MenuInfo
->dwStyle
| (ret
? topmenuI
.dwStyle
: 0);
3079 if (dwStyle
& MNS_NOTIFYBYPOS
)
3080 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
, MenuInfo
->iItem
, (LPARAM
)MenuInfo
->Self
);
3082 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
3086 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3092 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
3099 /***********************************************************************
3102 * Return TRUE if we can go on with menu tracking.
3104 static BOOL FASTCALL
3105 MENU_ButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
3108 ROSMENUINFO MenuInfo
;
3109 ROSMENUITEMINFO Item
;
3111 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
3115 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3119 if (IS_SYSTEM_MENU(&MenuInfo
))
3125 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3127 MenuInitRosMenuItemInfo(&Item
);
3128 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
3130 MenuCleanupRosMenuItemInfo(&Item
);
3134 if (!(Item
.fType
& MF_SEPARATOR
) &&
3135 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
3137 if (MenuInfo
.iItem
!= Index
)
3139 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3142 /* If the popup menu is not already "popped" */
3143 if (0 == (Item
.fState
& MF_MOUSESELECT
))
3145 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3149 MenuCleanupRosMenuItemInfo(&Item
);
3154 /* else the click was on the menu bar, finish the tracking */
3159 /***********************************************************************
3162 * Return the value of MenuExecFocusedItem if
3163 * the selected item was not a popup. Else open the popup.
3164 * A -1 return value indicates that we go on with menu tracking.
3168 MENU_ButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3171 ROSMENUINFO MenuInfo
;
3172 ROSMENUITEMINFO ItemInfo
;
3174 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
3179 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3184 if (! IS_SYSTEM_MENU(&MenuInfo
))
3186 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3188 MenuInitRosMenuItemInfo(&ItemInfo
);
3189 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
3190 MenuInfo
.iItem
== Id
)
3192 if (0 == (ItemInfo
.hSubMenu
))
3194 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
3195 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3196 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
3198 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3200 /* If we are dealing with the top-level menu */
3201 /* and this is a click on an already "popped" item: */
3202 /* Stop the menu tracking and close the opened submenus */
3203 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
3205 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3209 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3210 MenuInfo
.TimeToHide
= TRUE
;
3211 MenuSetRosMenuInfo(&MenuInfo
);
3217 /***********************************************************************
3220 * Walks menu chain trying to find a menu pt maps to.
3222 static HMENU FASTCALL
3223 MENU_PtMenu(HMENU hMenu
, POINT pt
)
3229 menu
= MENU_GetMenu( hMenu
);
3230 if (!menu
) return NULL
;
3232 /* try subpopup first (if any) */
3233 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3235 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3236 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3237 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3239 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
3240 ret
= MENU_PtMenu( UserHMGetHandle(pSubMenu
), pt
);
3244 /* check the current window (avoiding WM_HITTEST) */
3247 INT ht
= DefWndNCHitTest(menu
->hWnd
, pt
);
3248 if ( menu
->fFlags
& MNF_POPUP
)
3250 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
3252 else if (ht
== HTSYSMENU
)
3253 ret
= NtUserGetSystemMenu(menu
->hWnd
, FALSE
);
3254 else if (ht
== HTMENU
)
3255 ret
= GetMenu( menu
->hWnd
);
3260 /***********************************************************************
3263 * Return TRUE if we can go on with menu tracking.
3265 static BOOL FASTCALL
3266 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3269 ROSMENUINFO MenuInfo
;
3270 ROSMENUITEMINFO ItemInfo
;
3274 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3278 if (IS_SYSTEM_MENU(&MenuInfo
))
3284 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3289 Index
= NO_SELECTED_ITEM
;
3292 if (NO_SELECTED_ITEM
== Index
)
3294 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
3295 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3297 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3301 else if (MenuInfo
.iItem
!= Index
)
3303 MenuInitRosMenuItemInfo(&ItemInfo
);
3304 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
3305 !(ItemInfo
.fType
& MF_SEPARATOR
))
3307 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3308 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
3309 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3311 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3317 /***********************************************************************
3320 * Return the handle of the selected sub-popup menu (if any).
3323 HMENU
MENU_GetSubPopup( HMENU hmenu
)
3328 menu
= MENU_GetMenu( hmenu
);
3330 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3332 //item = &menu->rgItems[menu->iItem];
3333 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3334 if (item
) item
= &item
[menu
->iItem
];
3335 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3337 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
3338 return UserHMGetHandle(pSubMenu
);
3343 /***********************************************************************
3346 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3348 static LRESULT FASTCALL
3349 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
3351 ROSMENUINFO TopMenuInfo
;
3352 ROSMENUINFO MenuInfo
;
3354 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3356 return (LRESULT
) FALSE
;
3359 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.iItem
)
3360 || (VK_RIGHT
== Vk
&& TopMenuInfo
.iItem
== TopMenuInfo
.cItems
- 1))
3362 MDINEXTMENU NextMenu
;
3367 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
3368 NextMenu
.hmenuNext
= NULL
;
3369 NextMenu
.hwndNext
= NULL
;
3370 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3372 TRACE("%p [%p] -> %p [%p]\n",
3373 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3375 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3377 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
3378 NewWnd
= Mt
->OwnerWnd
;
3379 if (IS_SYSTEM_MENU(&TopMenuInfo
))
3381 /* switch to the menu bar */
3383 if (0 != (Style
& WS_CHILD
)
3384 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
3391 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
3395 Id
= MenuInfo
.cItems
- 1;
3398 else if (0 != (Style
& WS_SYSMENU
))
3400 /* switch to the system menu */
3401 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
3408 else /* application returned a new menu to switch to */
3410 NewMenu
= NextMenu
.hmenuNext
;
3411 NewWnd
= NextMenu
.hwndNext
;
3413 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
3415 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
3417 if (0 != (Style
& WS_SYSMENU
)
3418 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
3420 /* get the real system menu */
3421 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
3423 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
3425 /* FIXME: Not sure what to do here;
3426 * perhaps try to track NewMenu as a popup? */
3428 WARN(" -- got confused.\n");
3438 if (NewMenu
!= Mt
->TopMenu
)
3440 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3442 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3444 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3448 if (NewWnd
!= Mt
->OwnerWnd
)
3450 Mt
->OwnerWnd
= NewWnd
;
3451 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
3452 SetCapture(Mt
->OwnerWnd
); // 2
3455 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3456 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3458 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3467 /***********************************************************************
3470 * The idea is not to show the popup if the next input message is
3471 * going to hide it anyway.
3473 static BOOL FASTCALL
3474 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
3478 msg
.hwnd
= Mt
->OwnerWnd
;
3480 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
3481 //Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
3486 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3487 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3489 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3490 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3491 if( msg
.message
== WM_KEYDOWN
&&
3492 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3494 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3500 /* failures go through this */
3501 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3505 /***********************************************************************
3508 * Handle a VK_ESCAPE key event in a menu.
3510 static BOOL FASTCALL
3511 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3513 BOOL EndMenu
= TRUE
;
3514 ROSMENUINFO MenuInfo
;
3515 HMENU MenuTmp
, MenuPrev
;
3517 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3519 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3520 && 0 != (MenuInfo
.fFlags
& MNF_POPUP
))
3522 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3524 /* close topmost popup */
3525 while (MenuTmp
!= Mt
->CurrentMenu
)
3528 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3531 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3533 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3535 Mt
->CurrentMenu
= MenuPrev
;
3543 /***********************************************************************
3546 * Handle a VK_LEFT key event in a menu.
3548 static void FASTCALL
3549 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3551 ROSMENUINFO MenuInfo
;
3552 ROSMENUINFO TopMenuInfo
;
3553 ROSMENUINFO PrevMenuInfo
;
3554 HMENU MenuTmp
, MenuPrev
;
3557 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3559 /* Try to move 1 column left (if possible) */
3560 if ( (PrevCol
= MENU_GetStartOfPrevColumn(Mt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3562 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3564 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3569 /* close topmost popup */
3570 while (MenuTmp
!= Mt
->CurrentMenu
)
3573 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3576 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3580 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3581 Mt
->CurrentMenu
= MenuPrev
;
3583 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3587 if ((MenuPrev
== Mt
->TopMenu
) && !(TopMenuInfo
.fFlags
& MNF_POPUP
))
3589 /* move menu bar selection if no more popups are left */
3591 if (!MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3593 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3596 if (MenuPrev
!= MenuTmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3598 /* A sublevel menu was displayed - display the next one
3599 * unless there is another displacement coming up */
3601 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3602 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3604 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3611 /***********************************************************************
3614 * Handle a VK_RIGHT key event in a menu.
3616 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3619 ROSMENUINFO MenuInfo
;
3620 ROSMENUINFO CurrentMenuInfo
;
3623 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3624 Mt
->CurrentMenu
, Mt
->TopMenu
);
3626 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3627 if ((MenuInfo
.fFlags
& MNF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3629 /* If already displaying a popup, try to display sub-popup */
3631 hmenutmp
= Mt
->CurrentMenu
;
3632 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3634 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3637 /* if subpopup was displayed then we are done */
3638 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3641 /* Check to see if there's another column */
3642 if ( (NextCol
= MENU_GetStartOfNextColumn(Mt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3644 TRACE("Going to %d.\n", NextCol
);
3645 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3647 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3652 if (!(MenuInfo
.fFlags
& MNF_POPUP
)) /* menu bar tracking */
3654 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3656 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3657 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3664 /* try to move to the next item */
3665 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3666 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3668 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3670 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3671 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3673 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3680 /***********************************************************************
3683 * Menu tracking code.
3685 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3686 HWND hwnd
, const RECT
*lprect
)
3689 ROSMENUINFO MenuInfo
;
3690 ROSMENUITEMINFO ItemInfo
;
3693 INT executedMenuId
= -1;
3696 BOOL enterIdleSent
= FALSE
;
3699 mt
.CurrentMenu
= hmenu
;
3705 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3706 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3707 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3711 WARN("Invalid menu handle %p\n", hmenu
); // Error already set in IsMenu.
3715 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3720 if (wFlags
& TPM_BUTTONDOWN
)
3722 /* Get the result in order to start the tracking or not */
3723 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
3724 fEndMenu
= !fRemove
;
3727 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3729 /* owner may not be visible when tracking a popup, so use the menu itself */
3730 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3731 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3732 SetCapture(capture_win
); // 2
3736 BOOL ErrorExit
= FALSE
;
3737 menu
= MENU_GetMenu( mt
.CurrentMenu
);
3738 if (!menu
) /* sometimes happens if I do a window manager close */
3741 /* we have to keep the message in the queue until it's
3742 * clear that menu loop is not over yet. */
3746 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3748 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3749 /* remove the message from the queue */
3750 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3755 if (!ValidateHwndNoErr(mt
.OwnerWnd
) || !ValidateHwndNoErr(MenuInfo
.Wnd
))
3757 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3762 HWND win
= MenuInfo
.fFlags
& MNF_POPUP
? MenuInfo
.Wnd
: NULL
;
3763 enterIdleSent
= TRUE
;
3764 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3770 if (ErrorExit
) break; // Gracefully dropout.
3772 /* check if EndMenu() tried to cancel us, by posting this message */
3773 if (msg
.message
== WM_CANCELMODE
)
3775 /* we are now out of the loop */
3778 /* remove the message from the queue */
3779 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3781 /* break out of internal loop, ala ESCAPE */
3785 TranslateMessage( &msg
);
3788 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3789 enterIdleSent
=FALSE
;
3792 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3795 * Use the mouse coordinates in lParam instead of those in the MSG
3796 * struct to properly handle synthetic messages. They are already
3797 * in screen coordinates.
3799 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3800 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3802 /* Find a menu for this mouse event */
3803 hmenu
= MENU_PtMenu(mt
.TopMenu
, mt
.Pt
);
3807 /* no WM_NC... messages in captured state */
3809 case WM_RBUTTONDBLCLK
:
3810 case WM_RBUTTONDOWN
:
3811 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3813 case WM_LBUTTONDBLCLK
:
3814 case WM_LBUTTONDOWN
:
3815 /* If the message belongs to the menu, removes it from the queue */
3816 /* Else, end menu tracking */
3817 fRemove
= MENU_ButtonDown(&mt
, hmenu
, wFlags
);
3818 fEndMenu
= !fRemove
;
3822 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3825 /* Check if a menu was selected by the mouse */
3828 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
3829 TRACE("executedMenuId %d\n", executedMenuId
);
3831 /* End the loop if executedMenuId is an item ID */
3832 /* or if the job was done (executedMenuId = 0). */
3833 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3835 /* No menu was selected by the mouse */
3836 /* if the function was called by TrackPopupMenu, continue
3837 with the menu tracking. If not, stop it */
3839 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3844 /* the selected menu item must be changed every time */
3845 /* the mouse moves. */
3848 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3850 } /* switch(msg.message) - mouse */
3852 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3854 fRemove
= TRUE
; /* Keyboard messages are always removed */
3868 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3870 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3871 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3876 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3877 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3879 if (!(MenuInfo
.fFlags
& MNF_POPUP
))
3881 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3882 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3884 else /* otherwise try to move selection */
3885 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3890 MenuKeyLeft( &mt
, wFlags
);
3894 MenuKeyRight( &mt
, wFlags
);
3898 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3904 hi
.cbSize
= sizeof(HELPINFO
);
3905 hi
.iContextType
= HELPINFO_MENUITEM
;
3906 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3908 if (MenuInfo
.iItem
== NO_SELECTED_ITEM
)
3912 MenuInitRosMenuItemInfo(&ItemInfo
);
3913 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3917 hi
.iCtrlId
= ItemInfo
.wID
;
3923 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3926 hi
.hItemHandle
= hmenu
;
3927 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3928 hi
.MousePos
= msg
.pt
;
3929 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3936 break; /* WM_KEYDOWN */
3943 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3944 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3946 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3947 fEndMenu
= (executedMenuId
!= -2);
3951 /* Hack to avoid control chars. */
3952 /* We will find a better way real soon... */
3953 if (msg
.wParam
< 32) break;
3955 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
3956 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3957 else if (pos
== (UINT
)-1) MessageBeep(0);
3960 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
, TRUE
, 0);
3961 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3962 fEndMenu
= (executedMenuId
!= -2);
3966 } /* switch(msg.message) - kbd */
3970 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3971 DispatchMessageW( &msg
);
3975 if (!fEndMenu
) fRemove
= TRUE
;
3977 /* finally remove message from the queue */
3979 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3980 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3981 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3984 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3985 SetCapture(NULL
); /* release the capture */
3987 /* If dropdown is still painted and the close box is clicked on
3988 then the menu will be destroyed as part of the DispatchMessage above.
3989 This will then invalidate the menu handle in mt.hTopMenu. We should
3990 check for this first. */
3991 if( IsMenu( mt
.TopMenu
) )
3993 if (IsWindow(mt
.OwnerWnd
))
3995 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3997 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3999 if (MenuInfo
.fFlags
& MNF_POPUP
)
4001 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4002 DestroyWindow(MenuInfo
.Wnd
);
4003 MenuInfo
.Wnd
= NULL
;
4004 MenuSetRosMenuInfo(&MenuInfo
);
4006 if (!(wFlags
& TPM_NONOTIFY
))
4007 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
4008 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
4010 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
4013 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4016 /* Reset the variable for hiding menu */
4017 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4019 MenuInfo
.TimeToHide
= FALSE
;
4020 MenuSetRosMenuInfo(&MenuInfo
);
4024 /* The return value is only used by TrackPopupMenu */
4025 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4026 if (executedMenuId
== -1) executedMenuId
= 0;
4027 return executedMenuId
;
4030 /***********************************************************************
4033 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
4035 ROSMENUINFO MenuInfo
;
4037 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
4041 /* This makes the menus of applications built with Delphi work.
4042 * It also enables menus to be displayed in more than one window,
4043 * but there are some bugs left that need to be fixed in this case.
4045 if (!bPopup
&& (MenuGetRosMenuInfo(&MenuInfo
, hMenu
)))
4047 MenuInfo
.Wnd
= hWnd
;
4048 MenuSetRosMenuInfo(&MenuInfo
);
4050 //if (!bPopup) menu->hWnd = hWnd;
4053 top_popup
= MenuInfo
.Wnd
;//menu->hWnd;
4054 top_popup_hmenu
= hMenu
;
4059 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4060 if (!(wFlags
& TPM_NONOTIFY
))
4061 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
4063 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
4065 if (!(wFlags
& TPM_NONOTIFY
))
4067 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
4068 /* If an app changed/recreated menu bar entries in WM_INITMENU
4069 * menu sizes will be recalculated once the menu created/shown.
4072 if (!MenuInfo
.cyMenu
)
4074 /* app changed/recreated menu bar entries in WM_INITMENU
4075 Recalculate menu sizes else clicks will not work */
4076 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4077 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4082 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4084 MenuInfo
.fFlags
& MNF_SYSDESKMN
? OBJID_SYSMENU
: OBJID_MENU
,
4089 /***********************************************************************
4092 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
4094 TRACE("hwnd=%p\n", hWnd
);
4096 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4097 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
4100 top_popup_hmenu
= NULL
;
4104 /***********************************************************************
4105 * MenuTrackMouseMenuBar
4107 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4109 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
4111 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
4112 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4114 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
4116 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4119 /* map point to parent client coordinates */
4120 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
4121 if (Parent
!= GetDesktopWindow())
4123 ScreenToClient(Parent
, &pt
);
4126 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
4127 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
4128 MenuExitTracking(hWnd
, FALSE
);
4132 /***********************************************************************
4133 * MenuTrackKbdMenuBar
4135 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4137 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
4139 UINT uItem
= NO_SELECTED_ITEM
;
4141 ROSMENUINFO MenuInfo
;
4142 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4144 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
4146 /* find window that has a menu */
4148 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
4149 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
4150 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
4152 /* check if we have to track a system menu */
4154 hTrackMenu
= GetMenu( hwnd
);
4155 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
4157 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
4158 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
4160 wParam
|= HTSYSMENU
; /* prevent item lookup */
4163 if (!IsMenu( hTrackMenu
)) return;
4165 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
4167 /* fetch the window menu again, it may have changed */
4168 hTrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( hwnd
) : GetMenu( hwnd
);
4170 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
4175 if( wChar
&& wChar
!= ' ' )
4177 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4178 if ( uItem
>= (UINT
)(-2) )
4180 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
4181 /* schedule end of menu tracking */
4182 wFlags
|= TF_ENDMENU
;
4187 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
4189 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4191 if( uItem
== NO_SELECTED_ITEM
)
4192 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
4194 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
4198 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
4199 MenuExitTracking( hwnd
, FALSE
);
4202 /**********************************************************************
4203 * TrackPopupMenuEx (USER32.@)
4205 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, int x
, int y
,
4206 HWND hWnd
, LPTPMPARAMS lpTpm
)
4211 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
4212 hMenu
, wFlags
, x
, y
, hWnd
, lpTpm
,
4213 lpTpm
? wine_dbgstr_rect( &lpTpm
->rcExclude
) : "-" );
4215 /* Parameter check */
4216 /* FIXME: this check is performed several times, here and in the called
4217 functions. That could be optimized */
4218 if (!(menu
= MENU_GetMenu( hMenu
)))
4220 SetLastError( ERROR_INVALID_MENU_HANDLE
);
4224 if (IsWindow(menu
->hWnd
))
4226 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4230 if (MENU_InitPopup( hWnd
, hMenu
, wFlags
))
4232 MenuInitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
4234 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4235 if (!(wFlags
& TPM_NONOTIFY
))
4236 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
) hMenu
, 0);
4238 if (MenuShowPopup(hWnd
, hMenu
, 0, wFlags
, x
, y
, 0, 0 ))
4239 ret
= MenuTrackMenu(hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
,
4240 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4241 MenuExitTracking(hWnd
, TRUE
);
4245 ROSMENUINFO MenuInfo
;
4246 if (IsWindow( menu
->hWnd
)) // wine hack around this with their destroy function.
4247 DestroyWindow( menu
->hWnd
); // Fix wrong error return.
4249 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
4251 MenuSetRosMenuInfo(&MenuInfo
);
4253 if (!(wFlags
& TPM_NONOTIFY
))
4254 SendMessageW( hWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)hMenu
,
4255 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4261 /**********************************************************************
4262 * TrackPopupMenu (USER32.@)
4264 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
4265 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
4267 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
4270 /**********************************************************************
4273 * Uses flags, id and text ptr, passed by InsertMenu() and
4274 * ModifyMenu() to setup a MenuItemInfo structure.
4276 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
, LPMENUITEMINFOW pmii
, BOOL Unicode
)
4278 RtlZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
4279 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
4280 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
4281 /* setting bitmap clears text and vice versa */
4282 if( IS_STRING_ITEM(flags
)) {
4283 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
4285 flags
|= MF_SEPARATOR
;
4286 /* Item beginning with a backspace is a help item */
4287 /* FIXME: wrong place, this is only true in win16 */
4300 LPCSTR NewItemA
= (LPCSTR
) str
;
4301 if (*NewItemA
== '\b')
4305 str
= (LPCWSTR
) NewItemA
;
4307 TRACE("A cch %d\n",strlen(NewItemA
));
4310 pmii
->dwTypeData
= (LPWSTR
)str
;
4311 } else if( flags
& MFT_BITMAP
){
4312 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
4313 pmii
->hbmpItem
= (HBITMAP
)str
;
4315 if( flags
& MF_OWNERDRAW
){
4316 pmii
->fMask
|= MIIM_DATA
;
4317 pmii
->dwItemData
= (ULONG_PTR
) str
;
4319 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
4320 pmii
->fMask
|= MIIM_SUBMENU
;
4321 pmii
->hSubMenu
= (HMENU
)id
;
4323 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
4324 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
4325 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
4326 pmii
->wID
= (UINT
)id
;
4329 /**********************************************************************
4330 * MENU_NormalizeMenuItemInfoStruct
4332 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
4333 * check, copy and extend the MENUITEMINFO struct from the version that the application
4334 * supplied to the version used by wine source. */
4335 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
4336 MENUITEMINFOW
*pmii_out
)
4338 /* do we recognize the size? */
4339 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
4340 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
4341 SetLastError( ERROR_INVALID_PARAMETER
);
4344 /* copy the fields that we have */
4345 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
4346 /* if the hbmpItem member is missing then extend */
4347 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
4348 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
4349 pmii_out
->hbmpItem
= NULL
;
4351 /* test for invalid bit combinations */
4352 if( (pmii_out
->fMask
& MIIM_TYPE
&&
4353 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
4354 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
4355 ERR("invalid combination of fMask bits used\n");
4356 /* this does not happen on Win9x/ME */
4357 SetLastError( ERROR_INVALID_PARAMETER
);
4360 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
4361 if( pmii_out
->fMask
& MIIM_TYPE
){
4362 pmii_out
->fMask
|= MIIM_FTYPE
;
4363 if( IS_STRING_ITEM(pmii_out
->fType
)){
4364 pmii_out
->fMask
|= MIIM_STRING
;
4365 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
4366 pmii_out
->fMask
|= MIIM_BITMAP
;
4367 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
4370 if (pmii_out
->fMask
& MIIM_FTYPE
)
4372 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
4373 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
4375 if (pmii_out
->fMask
& MIIM_STATE
)
4376 /* Other menu items having MFS_DEFAULT are not converted
4378 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
4386 NONCLIENTMETRICSW ncm
;
4388 /* get the menu font */
4389 if(!hMenuFont
|| !hMenuFontBold
)
4391 ncm
.cbSize
= sizeof(ncm
);
4392 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
4394 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
4398 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4399 if(hMenuFont
== NULL
)
4401 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
4405 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
4406 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4407 if(hMenuFontBold
== NULL
)
4409 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
4410 DeleteObject(hMenuFont
);
4424 DeleteObject(hMenuFont
);
4430 DeleteObject(hMenuFontBold
);
4431 hMenuFontBold
= NULL
;
4436 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
4440 // Will be converted to load bitmaps for OBMI!
4442 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
4446 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
4448 PLOADMENU_CALLBACK_ARGUMENTS Common
;
4451 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
4453 Result
= (LRESULT
)LoadMenuW( Common
->hModule
, Common
->InterSource
? MAKEINTRESOURCE(Common
->InterSource
) : (LPCWSTR
)&Common
->MenuName
);
4455 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
4459 /* FUNCTIONS *****************************************************************/
4465 AppendMenuA(HMENU hMenu
,
4467 UINT_PTR uIDNewItem
,
4471 UNICODE_STRING UnicodeString
;
4474 RtlInitUnicodeString(&UnicodeString
, 0);
4476 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
4478 /* copy the text string, it will be one or the other */
4479 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4481 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
4483 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
4486 mii
.dwTypeData
= UnicodeString
.Buffer
;
4487 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4491 TRACE("AMA Handle bitmaps\n");
4493 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
4494 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &UnicodeString
);
4495 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
4503 AppendMenuW(HMENU hMenu
,
4505 UINT_PTR uIDNewItem
,
4509 UNICODE_STRING MenuText
;
4512 RtlInitUnicodeString(&MenuText
, 0);
4514 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
4516 /* copy the text string, it will be one or the other */
4517 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4519 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
4520 mii
.dwTypeData
= MenuText
.Buffer
;
4521 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4523 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &MenuText
);
4531 CheckMenuItem(HMENU hmenu
,
4539 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4542 if (!(item
= MENU_FindItem( &hmenu
, &uIDCheckItem
, uCheck
))) return -1;
4544 Ret
= item
->fState
& MFS_CHECKED
;
4545 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
4547 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4554 CheckMenuRadioItem(HMENU hMenu
,
4562 PITEM mi_first
= NULL
, mi_check
;
4563 HMENU m_first
, m_check
;
4565 mii
.cbSize
= sizeof( mii
);
4567 for (i
= first
; i
<= last
; i
++)
4574 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
4575 if (!mi_first
) continue;
4576 mi_check
= mi_first
;
4582 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
4583 if (!mi_check
) continue;
4586 if (m_first
!= m_check
) continue;
4587 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
4591 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
4593 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
4594 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
4595 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
4596 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4602 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
4603 if (mi_check
->fState
& MFS_CHECKED
)
4605 mii
.fMask
= MIIM_STATE
;
4606 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
4607 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4621 return NtUserxCreateMenu();
4628 CreatePopupMenu(VOID
)
4631 return NtUserxCreatePopupMenu();
4638 DrawMenuBar(HWND hWnd
)
4640 return NtUserxDrawMenuBar(hWnd
);
4647 EnableMenuItem(HMENU hMenu
,
4651 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4661 guii
.cbSize
= sizeof(GUITHREADINFO
);
4662 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4666 guii
.hwndMenuOwner
!= top_popup
)
4668 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4672 /* if we are in the menu code, and it is active */
4673 if (!fEndMenu
&& top_popup
)
4675 /* terminate the menu handling code */
4678 /* needs to be posted to wakeup the internal menu handler */
4679 /* which will now terminate the menu, in the event that */
4680 /* the main window was minimized, or lost focus, so we */
4681 /* don't end up with an orphaned menu */
4682 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4687 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4690 ROSMENUINFO MenuInfo
;
4691 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4692 // Force bits to be set call server side....
4693 // This alone works and passes all the menu test_menu_hilitemenuitem tests.
4694 if (!NtUserHiliteMenuItem(hWnd
, hMenu
, wItemID
, wHilite
)) return FALSE
;
4695 // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
4697 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
4699 if (MenuInfo
.iItem
== wItemID
) return TRUE
;
4700 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4701 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4703 return TRUE
; // Always returns TRUE!
4712 PWND Wnd
= ValidateHwnd(hWnd
);
4717 return UlongToHandle(Wnd
->IDMenu
);
4723 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4726 Ret
= NtUserGetMenuBarInfo( hwnd
, idObject
, idItem
, pmbi
);
4727 // Reason to move to server side!!!!!
4728 if (!Ret
) return Ret
;
4730 pmbi
->fBarFocused
= top_popup_hmenu
== pmbi
->hMenu
;
4733 pmbi
->fFocused
= pmbi
->fBarFocused
;
4743 GetMenuCheckMarkDimensions(VOID
)
4745 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4746 GetSystemMetrics(SM_CYMENUCHECK
)));
4754 GetMenuContextHelpId(HMENU hmenu
)
4757 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4758 return pMenu
->dwContextHelpId
;
4766 GetMenuDefaultItem(HMENU hMenu
,
4772 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
4775 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
4782 GetMenuInfo(HMENU hmenu
,
4787 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4789 SetLastError(ERROR_INVALID_PARAMETER
);
4793 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4796 if (lpcmi
->fMask
& MIM_BACKGROUND
)
4797 lpcmi
->hbrBack
= pMenu
->hbrBack
;
4799 if (lpcmi
->fMask
& MIM_HELPID
)
4800 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
4802 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
4803 lpcmi
->cyMax
= pMenu
->cyMax
;
4805 if (lpcmi
->fMask
& MIM_MENUDATA
)
4806 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
4808 if (lpcmi
->fMask
& MIM_STYLE
)
4809 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
4818 GetMenuItemCount(HMENU hmenu
)
4821 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4822 return pMenu
->cItems
;
4830 GetMenuItemID(HMENU hMenu
,
4834 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
4835 if (lpmi
->spSubMenu
) return -1;
4847 LPMENUITEMINFOA lpmii
)
4852 if( lpmii
->cbSize
!= sizeof( mii
) &&
4853 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4855 SetLastError( ERROR_INVALID_PARAMETER
);
4858 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4859 mii
.cbSize
= sizeof( mii
);
4860 ret
= GetMenuItemInfo_common (hmenu
,
4863 (LPMENUITEMINFOW
)&mii
,
4865 mii
.cbSize
= lpmii
->cbSize
;
4866 memcpy( lpmii
, &mii
, mii
.cbSize
);
4878 LPMENUITEMINFOW lpmii
)
4882 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4884 SetLastError( ERROR_INVALID_PARAMETER
);
4887 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4888 mii
.cbSize
= sizeof( mii
);
4889 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
4890 mii
.cbSize
= lpmii
->cbSize
;
4891 memcpy( lpmii
, &mii
, mii
.cbSize
);
4907 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
4908 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
4910 if (!pItem
->Xlpstr
&& pItem
->hbmp
) Type
= MFT_BITMAP
;
4912 if (pItem
->spSubMenu
)
4914 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
4915 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
4916 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
4917 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|Type
) & 0xff);
4920 return (pItem
->fType
| pItem
->fState
| Type
);
4937 ////// wine Code, seems to be faster.
4938 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
4940 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
4942 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
4944 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
4948 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
4950 if (!text
) return 0;
4951 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
4952 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
4953 lpString
[nMaxCount
-1] = 0;
4954 TRACE("A returning %s\n", lpString
);
4955 return strlen(lpString
);
4973 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
4975 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
4977 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
4979 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
4983 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
4985 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
4991 lstrcpynW( lpString
, text
, nMaxCount
);
4992 TRACE("W returning %S\n", lpString
);
4993 return strlenW(lpString
);
5006 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
5008 if (pItem
->spSubMenu
)
5010 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
5011 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
5012 if (IsMenu(hsubmenu
)) return hsubmenu
;
5028 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
5030 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
5042 UINT_PTR uIDNewItem
,
5046 UNICODE_STRING UnicodeString
;
5049 RtlInitUnicodeString(&UnicodeString
, 0);
5051 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5053 /* copy the text string, it will be one or the other */
5054 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5056 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5058 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5061 mii
.dwTypeData
= UnicodeString
.Buffer
;
5062 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5066 TRACE("Handle bitmaps\n");
5068 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &UnicodeString
);
5069 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5082 LPCMENUITEMINFOA lpmii
)
5085 UNICODE_STRING UnicodeString
;
5088 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5090 RtlInitUnicodeString(&UnicodeString
, 0);
5092 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5094 /* copy the text string */
5095 if (((mii
.fMask
& MIIM_STRING
) ||
5096 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5097 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5099 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5101 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5104 mii
.dwTypeData
= UnicodeString
.Buffer
;
5105 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5109 TRACE("Handle bitmaps\n");
5111 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
5112 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5125 LPCMENUITEMINFOW lpmii
)
5128 UNICODE_STRING MenuText
;
5131 /* while we could just pass 'lpmii' to win32k, we make a copy so that
5132 if a bad user passes bad data, we crash his process instead of the
5135 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5137 RtlInitUnicodeString(&MenuText
, 0);
5139 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5141 /* copy the text string */
5142 if (((mii
.fMask
& MIIM_STRING
) ||
5143 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5144 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5146 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
5147 mii
.dwTypeData
= MenuText
.Buffer
;
5148 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5150 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
5163 UINT_PTR uIDNewItem
,
5167 UNICODE_STRING MenuText
;
5170 RtlInitUnicodeString(&MenuText
, 0);
5172 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5174 /* copy the text string, it will be one or the other */
5175 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5177 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5178 mii
.dwTypeData
= MenuText
.Buffer
;
5179 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5181 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &MenuText
);
5193 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
5201 LoadMenuA(HINSTANCE hInstance
,
5204 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
5205 if (Resource
== NULL
)
5209 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
5216 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
5218 return(LoadMenuIndirectW(lpMenuTemplate
));
5225 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
5228 WORD version
, offset
;
5229 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
5231 version
= GET_WORD(p
);
5236 case 0: /* standard format is version of 0 */
5237 offset
= GET_WORD(p
);
5238 p
+= sizeof(WORD
) + offset
;
5239 if (!(hMenu
= CreateMenu())) return 0;
5240 if (!MENU_ParseResource(p
, hMenu
))
5246 case 1: /* extended format is version of 1 */
5247 offset
= GET_WORD(p
);
5248 p
+= sizeof(WORD
) + offset
;
5249 if (!(hMenu
= CreateMenu())) return 0;
5250 if (!MENUEX_ParseResource(p
, hMenu
))
5252 DestroyMenu( hMenu
);
5257 ERR("Menu template version %d not supported.\n", version
);
5266 LoadMenuW(HINSTANCE hInstance
,
5269 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
5270 if (Resource
== NULL
)
5274 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
5287 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
5299 UINT_PTR uIDNewItem
,
5303 UNICODE_STRING UnicodeString
;
5306 RtlInitUnicodeString(&UnicodeString
, 0);
5308 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5310 /* copy the text string, it will be one or the other */
5311 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5313 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5315 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5318 mii
.dwTypeData
= UnicodeString
.Buffer
;
5319 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5323 TRACE("Handle bitmaps\n");
5325 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &UnicodeString
);
5326 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5339 UINT_PTR uIDNewItem
,
5343 UNICODE_STRING MenuText
;
5346 RtlInitUnicodeString(&MenuText
, 0);
5348 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5350 /* copy the text string, it will be one or the other */
5351 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5353 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5354 mii
.dwTypeData
= MenuText
.Buffer
;
5355 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5359 TRACE("Handle bitmaps\n");
5361 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &MenuText
);
5372 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
5387 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
5389 SetLastError(ERROR_INVALID_PARAMETER
);
5393 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5394 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
5406 HBITMAP hBitmapUnchecked
,
5407 HBITMAP hBitmapChecked
)
5409 MENUITEMINFOW uItem
;
5410 memset ( &uItem
, 0, sizeof(uItem
) );
5411 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
5412 uItem
.fMask
= MIIM_CHECKMARKS
;
5413 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5414 uItem
.hbmpChecked
= hBitmapChecked
;
5415 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
5427 LPCMENUITEMINFOA lpmii
)
5430 UNICODE_STRING UnicodeString
;
5433 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
5435 RtlInitUnicodeString(&UnicodeString
, 0);
5437 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5439 * MIIM_STRING == good
5440 * MIIM_TYPE & MFT_STRING == good
5441 * MIIM_STRING & MFT_STRING == good
5442 * MIIM_STRING & MFT_OWNERDRAW == good
5444 if (((mii
.fMask
& MIIM_STRING
) ||
5445 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5446 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5448 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5449 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5451 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5454 mii
.dwTypeData
= UnicodeString
.Buffer
;
5455 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5459 UnicodeString
.Buffer
= NULL
;
5461 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
5462 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
5475 LPCMENUITEMINFOW lpmii
)
5477 MENUITEMINFOW MenuItemInfoW
;
5478 UNICODE_STRING UnicodeString
;
5481 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5483 RtlInitUnicodeString(&UnicodeString
, 0);
5485 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
5487 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5488 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5489 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5490 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
5492 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
5493 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5495 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
5511 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5516 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5519 return NtUserSetSystemMenu(hwnd
, hMenu
);
5523 // Example for the Win32/User32 rewrite.
5524 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5538 return NtUserTrackPopupMenuEx( Menu
,
5543 NULL
); // LPTPMPARAMS is null
5562 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5565 Result
= (ULONG_PTR
)lResult
;
5570 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5589 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5592 Result
= (ULONG_PTR
)lResult
;
5597 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5608 LPCWSTR lpszNewItem
,
5613 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5614 for MF_DELETE. We should check the parameters for all others
5615 MF_* actions also (anybody got a doc on ChangeMenu?).
5618 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5621 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5624 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5627 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5630 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5631 flags
&~ MF_REMOVE
);
5633 default : /* MF_INSERT */
5634 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5651 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5652 for MF_DELETE. We should check the parameters for all others
5653 MF_* actions also (anybody got a doc on ChangeMenu?).
5656 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5659 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5662 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5665 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5668 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5669 flags
&~ MF_REMOVE
);
5671 default : /* MF_INSERT */
5672 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);